blob: c0e249a0e48602b9813f31cb28a8e6d580471a2e [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.npw;
import com.android.SdkConstants;
import com.android.assetstudiolib.ActionBarIconGenerator;
import com.android.assetstudiolib.GraphicGenerator;
import com.android.resources.Density;
import com.android.tools.idea.templates.Template;
import com.android.tools.idea.templates.TemplateManager;
import com.android.tools.idea.templates.TemplateMetadata;
import com.android.tools.idea.ui.ComboBoxItemWithApiTag;
import com.android.tools.idea.ui.ImageComponent;
import com.android.tools.idea.templates.StringEvaluator;
import com.android.tools.idea.wizard.template.TemplateWizardState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.ColorPanel;
import com.intellij.ui.components.JBScrollPane;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.Callable;
import static com.android.tools.idea.npw.AssetStudioAssetGenerator.*;
/**
* {@linkplain RasterAssetSetStep} is a wizard page that lets the user create a variety of density-scaled assets.
*/
public class RasterAssetSetStep extends CommonAssetSetStep {
private static final Logger LOG = Logger.getInstance(RasterAssetSetStep.class);
private static final int CLIPART_ICON_SIZE = 32;
private static final int CLIPART_DIALOG_BORDER = 10;
private static final int DIALOG_HEADER = 20;
public static final String ATTR_ICON_RESOURCE = "icon_resource";
private static final String V11 = "V11";
private static final String V9 = "V9";
public static final String IMAGES_CLIPART_BIG = "images/clipart/big/";
private JPanel myPanel;
private JRadioButton myImageRadioButton;
private JRadioButton myClipartRadioButton;
private JRadioButton myTextRadioButton;
private JRadioButton myCropRadioButton;
private JRadioButton myCenterRadioButton;
private JRadioButton myCircleRadioButton;
private JRadioButton mySquareRadioButton;
private JRadioButton myNoneRadioButton;
private JButton myChooseClipart;
private JLabel myError;
private JLabel myDescription;
private JCheckBox myTrimBlankSpace;
private JTextField myText;
private JComboBox myFontFamily;
private TextFieldWithBrowseButton myImageFile;
private ColorPanel myBackgroundColor;
private ColorPanel myForegroundColor;
private ImageComponent myMdpiPreview;
private ImageComponent myHdpiPreview;
private ImageComponent myXHdpiPreview;
private JSlider myPaddingSlider;
private ImageComponent myXXHdpiPreview;
private JLabel myImageFileLabel;
private JLabel myTextLabel;
private JLabel myFontFamilyLabel;
private JLabel myChooseClipartLabel;
private JLabel myBackgroundColorLabel;
private JLabel myForegroundColorLabel;
private JComboBox myAssetTypeComboBox;
private JLabel myAssetTypeLabel;
private JComboBox myChooseThemeComboBox;
private JLabel myChooseThemeLabel;
private JLabel myForegroundScalingLabel;
private JLabel myShapeLabel;
private JPanel myShapePanel;
private JPanel myScalingPanel;
private JTextField myResourceNameField;
private JLabel myResourceNameLabel;
private JPanel myVersionPanel;
private ImageComponent myV9XHdpiPreview;
private ImageComponent myV9XXHdpiPreview;
private ImageComponent myV9MdpiPreview;
private ImageComponent myV9HdpiPreview;
private ImageComponent myV11MdpiPreview;
private ImageComponent myV11HdpiPreview;
private ImageComponent myV11XHdpiPreview;
private ImageComponent myV11XXHdpiPreview;
private ImageComponent myXXXHdpiPreview;
private JRadioButton myVerticalRadioButton;
private JRadioButton myHorizontalRadioButton;
private JLabel myXXXHDPILabel;
private JCheckBox myDogEarEffectCheckBox;
private JBScrollPane myScrollPane;
private final StringEvaluator myStringEvaluator = new StringEvaluator();
@SuppressWarnings("UseJBColor") // Colors are used for the graphics generator, not the plugin UI
public RasterAssetSetStep(TemplateWizardState state,
@Nullable Project project,
@Nullable Module module,
@Nullable Icon sidePanelIcon,
UpdateListener updateListener,
@Nullable VirtualFile invocationTarget) {
super(state, project, module, sidePanelIcon, updateListener, invocationTarget);
// Speed the scrolling of myScrollPane
myScrollPane.getVerticalScrollBar().setUnitIncrement(16);
register(ATTR_TEXT, myText);
register(ATTR_SCALING, myCropRadioButton, Scaling.CROP);
register(ATTR_SCALING, myCenterRadioButton, Scaling.CENTER);
register(ATTR_SHAPE, myCircleRadioButton, GraphicGenerator.Shape.CIRCLE);
register(ATTR_SHAPE, myNoneRadioButton, GraphicGenerator.Shape.NONE);
register(ATTR_SHAPE, mySquareRadioButton, GraphicGenerator.Shape.SQUARE);
register(ATTR_SHAPE, myVerticalRadioButton, GraphicGenerator.Shape.VRECT);
register(ATTR_SHAPE, myHorizontalRadioButton, GraphicGenerator.Shape.HRECT);
register(ATTR_DOGEAR, myDogEarEffectCheckBox);
register(ATTR_PADDING, myPaddingSlider);
register(ATTR_TRIM, myTrimBlankSpace);
register(ATTR_FONT, myFontFamily);
register(ATTR_SOURCE_TYPE, myImageRadioButton, AssetStudioAssetGenerator.SourceType.IMAGE);
register(ATTR_SOURCE_TYPE, myClipartRadioButton, AssetStudioAssetGenerator.SourceType.CLIPART);
register(ATTR_SOURCE_TYPE, myTextRadioButton, AssetStudioAssetGenerator.SourceType.TEXT);
register(ATTR_FOREGROUND_COLOR, myForegroundColor);
register(ATTR_BACKGROUND_COLOR, myBackgroundColor);
register(ATTR_ASSET_TYPE, myAssetTypeComboBox);
register(ATTR_ASSET_THEME, myChooseThemeComboBox);
register(ATTR_ASSET_NAME, myResourceNameField);
myImageFile.addBrowseFolderListener(null, null, null, FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor());
myForegroundColor.setSelectedColor(Color.BLUE);
myBackgroundColor.setSelectedColor(Color.WHITE);
for (String font : GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()) {
myFontFamily.addItem(new ComboBoxItemWithApiTag(font, font, 1, 1));
if (font.equals(myTemplateState.get(ATTR_FONT))) {
myFontFamily.setSelectedIndex(myFontFamily.getItemCount() - 1);
}
}
myChooseClipart.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
displayClipartDialog();
}
});
populateComboBox(myAssetTypeComboBox, AssetType.class);
populateComboBox(myChooseThemeComboBox, ActionBarIconGenerator.Theme.class);
}
@Override
public void deriveValues() {
super.deriveValues();
myTemplateState.put(ATTR_ICON_RESOURCE, myTemplateState.getString(ATTR_ASSET_NAME));
// Source Radio button
if (myImageRadioButton.isSelected()) {
hide(myChooseClipart, myChooseClipartLabel, myText, myTextLabel, myFontFamily, myFontFamilyLabel, myForegroundColor,
myForegroundColorLabel);
show(myImageFile, myImageFileLabel, myBackgroundColor, myBackgroundColorLabel);
} else if (myClipartRadioButton.isSelected()) {
hide(myText, myTextLabel, myFontFamily, myFontFamilyLabel, myImageFile, myImageFileLabel);
show(myChooseClipart, myChooseClipartLabel, myBackgroundColor, myBackgroundColorLabel,myForegroundColor, myForegroundColorLabel);
} else if (myTextRadioButton.isSelected()) {
hide(myChooseClipart, myChooseClipartLabel, myImageFile, myImageFileLabel);
show(myText, myTextLabel, myFontFamily, myFontFamilyLabel, myBackgroundColor, myBackgroundColorLabel, myForegroundColor,
myForegroundColorLabel);
myFontFamily.setSelectedItem(myTemplateState.getString(ATTR_FONT));
}
// Asset Type Combo Box
if (myTemplateState.get(ATTR_ASSET_TYPE) != null) {
final AssetType selectedAssetType = AssetType.valueOf(myTemplateState.getString(ATTR_ASSET_TYPE));
mySelectedAssetType = selectedAssetType;
if (selectedAssetType != null) {
switch (selectedAssetType) {
case LAUNCHER:
hide(myChooseThemeComboBox, myChooseThemeLabel, myVersionPanel,
myDogEarEffectCheckBox);
show(myForegroundScalingLabel, myScalingPanel, myShapeLabel, myShapePanel,
myResourceNameLabel, myResourceNameField, myXXXHdpiPreview, myXXXHDPILabel, myScrollPane);
if (!myTemplateState.myModified.contains(ATTR_ASSET_NAME)) {
myTemplateState.put(ATTR_ASSET_NAME, "icon");
}
//Dog-ear effect
if(mySquareRadioButton.isSelected() || myVerticalRadioButton .isSelected()
|| myHorizontalRadioButton.isSelected()) {
show(myDogEarEffectCheckBox);
}
break;
case ACTIONBAR:
show(myResourceNameField, myResourceNameLabel);
show(myChooseThemeComboBox, myChooseThemeLabel, myScrollPane);
hide(myForegroundScalingLabel, myScalingPanel, myShapeLabel, myShapePanel,
myBackgroundColorLabel, myBackgroundColor, myVersionPanel, myXXXHdpiPreview,
myXXXHDPILabel, myDogEarEffectCheckBox);
break;
case NOTIFICATION:
show(myResourceNameField, myResourceNameLabel, myVersionPanel);
hide(myChooseThemeComboBox, myChooseThemeLabel, myForegroundColor, myForegroundColorLabel);
hide(myForegroundScalingLabel, myScalingPanel, myShapeLabel, myShapePanel,
myBackgroundColorLabel, myBackgroundColor, myScrollPane, myDogEarEffectCheckBox);
break;
}
if (!myTemplateState.myModified.contains(ATTR_ASSET_NAME)) {
updateDerivedValue(ATTR_ASSET_NAME, myResourceNameField, new Callable<String>() {
@Override
public String call() throws Exception {
return computeResourceName();
}
});
}
}
}
// Theme chooser
if (myChooseThemeComboBox.isVisible() && myTemplateState.hasAttr(ATTR_ASSET_THEME)) {
if (ActionBarIconGenerator.Theme.valueOf(myTemplateState.getString(ATTR_ASSET_THEME))
.equals(ActionBarIconGenerator.Theme.CUSTOM)) {
show(myForegroundColor, myForegroundColorLabel);
} else {
hide(myForegroundColor, myForegroundColorLabel);
}
}
}
@Override
protected void updatePreviewImages() {
if (mySelectedAssetType == null || myImageMap == null) {
return;
}
if (mySelectedAssetType.equals(AssetType.NOTIFICATION)) {
final BufferedImage v9_mdpi = getImage(myImageMap, V9, Density.MEDIUM);
final BufferedImage v9_hdpi = getImage(myImageMap, V9, Density.HIGH);
final BufferedImage v9_xhdpi = getImage(myImageMap, V9, Density.XHIGH);
final BufferedImage v9_xxhdpi = getImage(myImageMap, V9, Density.XXHIGH);
setIconOrClear(myV9MdpiPreview, v9_mdpi);
setIconOrClear(myV9HdpiPreview, v9_hdpi);
setIconOrClear(myV9XHdpiPreview, v9_xhdpi);
setIconOrClear(myV9XXHdpiPreview, v9_xxhdpi);
final BufferedImage v11_mdpi = getImage(myImageMap, V11, Density.MEDIUM);
final BufferedImage v11_hdpi = getImage(myImageMap, V11, Density.HIGH);
final BufferedImage v11_xhdpi = getImage(myImageMap, V11, Density.XHIGH);
final BufferedImage v11_xxhdpi = getImage(myImageMap, V11, Density.XXHIGH);
setIconOrClear(myV11MdpiPreview, v11_mdpi);
setIconOrClear(myV11HdpiPreview, v11_hdpi);
setIconOrClear(myV11XHdpiPreview, v11_xhdpi);
setIconOrClear(myV11XXHdpiPreview, v11_xxhdpi);
} else {
final BufferedImage mdpi = getImage(myImageMap, Density.MEDIUM.getResourceValue());
final BufferedImage hdpi = getImage(myImageMap, Density.HIGH.getResourceValue());
final BufferedImage xhdpi = getImage(myImageMap, Density.XHIGH.getResourceValue());
final BufferedImage xxhdpi = getImage(myImageMap, Density.XXHIGH.getResourceValue());
setIconOrClear(myMdpiPreview, mdpi);
setIconOrClear(myHdpiPreview, hdpi);
setIconOrClear(myXHdpiPreview, xhdpi);
setIconOrClear(myXXHdpiPreview, xxhdpi);
if (mySelectedAssetType.equals(AssetType.LAUNCHER)) {
final BufferedImage xxxhdpi = getImage(myImageMap, Density.XXXHIGH.getResourceValue());
setIconOrClear(myXXXHdpiPreview, xxxhdpi);
}
}
myUpdateListener.update();
}
/**
* Displays a modal dialog with one button for each entry in the {@link GraphicGenerator} clipart library. Clicking on a button sets that
* entry into the {@link ATTR_CLIPART_NAME} parameter.
*/
private void displayClipartDialog() {
Window window = SwingUtilities.getWindowAncestor(myPanel);
final JDialog dialog = new JDialog(window, Dialog.ModalityType.DOCUMENT_MODAL);
FlowLayout layout = new FlowLayout();
dialog.getRootPane().setLayout(layout);
int count = 0;
for (Iterator<String> iter = GraphicGenerator.getResourcesNames(IMAGES_CLIPART_BIG, SdkConstants.DOT_PNG);
iter.hasNext(); ) {
final String name = iter.next();
try {
JButton btn = new JButton();
btn.setIcon(new ImageIcon(GraphicGenerator.getClipartIcon(name)));
Dimension d = new Dimension(CLIPART_ICON_SIZE, CLIPART_ICON_SIZE);
btn.setMaximumSize(d);
btn.setPreferredSize(d);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
myTemplateState.put(ATTR_CLIPART_NAME, name);
dialog.setVisible(false);
update();
}
});
dialog.getRootPane().add(btn);
count++;
}
catch (IOException e) {
LOG.error(e);
}
}
int size = (int)(Math.sqrt(count) + 1) * (CLIPART_ICON_SIZE + layout.getHgap()) + CLIPART_DIALOG_BORDER * 2;
dialog.setSize(size, size + DIALOG_HEADER);
dialog.setLocationRelativeTo(window);
dialog.setVisible(true);
}
public void finalizeAssetType(AssetType type) {
mySelectedAssetType = type;
myTemplateState.put(ATTR_ASSET_TYPE, type.name());
for (int i = 0; i < myAssetTypeComboBox.getItemCount(); ++i) {
if (((ComboBoxItemWithApiTag)myAssetTypeComboBox.getItemAt(i)).id.equals(type.name())) {
myAssetTypeComboBox.setSelectedIndex(i);
break;
}
}
hide(myAssetTypeComboBox, myAssetTypeLabel);
update();
}
@Nullable
private static BufferedImage getImage(@NotNull Map<String, Map<String, BufferedImage>> map, @NotNull String name) {
final Map<String, BufferedImage> images = map.get(name);
if (images == null) {
return null;
}
final Collection<BufferedImage> values = images.values();
return values.isEmpty() ? null : values.iterator().next();
}
@Nullable
private static BufferedImage getImage(@NotNull Map<String, Map<String, BufferedImage>> map,
@NotNull String category, @NotNull Density density) {
String densityString = density.getResourceValue();
final Map<String, BufferedImage> images = map.get(category);
if (images == null) {
return null;
}
for (String key : images.keySet()) {
if (key.contains(densityString)) {
return images.get(key);
}
}
return null;
}
@Override
public JComponent getComponent() {
return myPanel;
}
@Override
public String getHelpId() {
return "Android-Gradle_Screen_Configuration_Page";
}
@Override
protected void initialize() {
myTemplateState.put(ATTR_IMAGE_PATH, new File(TemplateManager.getTemplateRootFolder(), FileUtil
.join(Template.CATEGORY_PROJECTS, NewProjectWizardState.MODULE_TEMPLATE_NAME, "root", "res", "mipmap-xhdpi", "ic_launcher.png"))
.getAbsolutePath());
register(ATTR_IMAGE_PATH, myImageFile);
}
@NotNull
@Override
protected String computeResourceName() {
String resourceName = null;
if (myTemplateState.get(TemplateMetadata.ATTR_ICON_NAME) != null) {
resourceName = myStringEvaluator.evaluate(myTemplateState.getString(TemplateMetadata.ATTR_ICON_NAME), myTemplateState.getParameters());
}
if (resourceName == null) {
resourceName = String.format(mySelectedAssetType.getDefaultNameFormat(), "name");
}
// It's unusual to have > 1 launcher icon, don't fix the name for launcher icons.
if (drawableExists(resourceName) && mySelectedAssetType != AssetType.LAUNCHER) {
// While uniqueness isn't satisfied, increment number and add to end
int i = 2;
while (drawableExists(resourceName + Integer.toString(i))) {
i++;
}
resourceName += Integer.toString(i);
}
return resourceName;
}
@Override
protected void generateAssetFiles(File targetResDir) {
File targetVariantDir = targetResDir.getParentFile();
myAssetGenerator.outputImagesIntoVariantRoot(targetVariantDir);
}
@Override
public JComponent getPreferredFocusedComponent() {
return myImageRadioButton;
}
@NotNull
@Override
protected JLabel getDescription() {
return myDescription;
}
@NotNull
@Override
protected JLabel getError() {
return myError;
}
}