1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.eclipse.org/org/documents/epl-v10.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ide.eclipse.adt.internal.assetstudio; 18 19 import static com.android.ide.eclipse.adt.internal.wizards.templates.NewProjectWizard.DEFAULT_LAUNCHER_ICON; 20 import static java.awt.image.BufferedImage.TYPE_INT_ARGB; 21 22 import com.android.annotations.NonNull; 23 import com.android.annotations.Nullable; 24 import com.android.assetstudiolib.ActionBarIconGenerator; 25 import com.android.assetstudiolib.GraphicGenerator; 26 import com.android.assetstudiolib.GraphicGenerator.Shape; 27 import com.android.assetstudiolib.LauncherIconGenerator; 28 import com.android.assetstudiolib.MenuIconGenerator; 29 import com.android.assetstudiolib.NotificationIconGenerator; 30 import com.android.assetstudiolib.TabIconGenerator; 31 import com.android.assetstudiolib.TextRenderUtil; 32 import com.android.assetstudiolib.Util; 33 import com.android.ide.eclipse.adt.AdtPlugin; 34 import com.android.ide.eclipse.adt.AdtUtils; 35 import com.android.ide.eclipse.adt.internal.assetstudio.CreateAssetSetWizardState.SourceType; 36 import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageControl; 37 import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageUtils; 38 import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SwtUtils; 39 import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo; 40 import com.android.utils.Pair; 41 42 import org.eclipse.core.resources.IFile; 43 import org.eclipse.core.resources.IProject; 44 import org.eclipse.core.resources.IResource; 45 import org.eclipse.core.resources.IWorkspaceRoot; 46 import org.eclipse.core.resources.ResourcesPlugin; 47 import org.eclipse.core.runtime.CoreException; 48 import org.eclipse.core.runtime.IPath; 49 import org.eclipse.core.runtime.IStatus; 50 import org.eclipse.core.runtime.NullProgressMonitor; 51 import org.eclipse.core.runtime.Path; 52 import org.eclipse.jface.dialogs.IMessageProvider; 53 import org.eclipse.jface.dialogs.MessageDialog; 54 import org.eclipse.jface.wizard.WizardPage; 55 import org.eclipse.swt.SWT; 56 import org.eclipse.swt.custom.ScrolledComposite; 57 import org.eclipse.swt.custom.StackLayout; 58 import org.eclipse.swt.events.ModifyEvent; 59 import org.eclipse.swt.events.ModifyListener; 60 import org.eclipse.swt.events.MouseAdapter; 61 import org.eclipse.swt.events.MouseEvent; 62 import org.eclipse.swt.events.SelectionEvent; 63 import org.eclipse.swt.events.SelectionListener; 64 import org.eclipse.swt.graphics.Color; 65 import org.eclipse.swt.graphics.Font; 66 import org.eclipse.swt.graphics.FontData; 67 import org.eclipse.swt.graphics.Image; 68 import org.eclipse.swt.graphics.RGB; 69 import org.eclipse.swt.layout.GridData; 70 import org.eclipse.swt.layout.GridLayout; 71 import org.eclipse.swt.layout.RowData; 72 import org.eclipse.swt.layout.RowLayout; 73 import org.eclipse.swt.widgets.Button; 74 import org.eclipse.swt.widgets.ColorDialog; 75 import org.eclipse.swt.widgets.Composite; 76 import org.eclipse.swt.widgets.Control; 77 import org.eclipse.swt.widgets.Display; 78 import org.eclipse.swt.widgets.FileDialog; 79 import org.eclipse.swt.widgets.FontDialog; 80 import org.eclipse.swt.widgets.Label; 81 import org.eclipse.swt.widgets.Slider; 82 import org.eclipse.swt.widgets.Text; 83 84 import java.awt.Paint; 85 import java.awt.image.BufferedImage; 86 import java.io.ByteArrayInputStream; 87 import java.io.ByteArrayOutputStream; 88 import java.io.File; 89 import java.io.IOException; 90 import java.io.InputStream; 91 import java.util.Collections; 92 import java.util.Iterator; 93 import java.util.LinkedHashMap; 94 import java.util.Map; 95 import java.util.Map.Entry; 96 97 import javax.imageio.ImageIO; 98 99 /** 100 * This is normally page 2 of a Create New Asset Set wizard, unless we can offer actions 101 * to create a specific asset type, in which case we skip page 1. On this page the user 102 * gets to configure the parameters of the asset, and see a preview. 103 */ 104 public class ConfigureAssetSetPage extends WizardPage implements SelectionListener, 105 ModifyListener { 106 private final CreateAssetSetWizardState mValues; 107 108 private static final int PREVIEW_AREA_WIDTH = 144; 109 110 private boolean mShown; 111 112 private Composite mConfigurationArea; 113 private Button mImageRadio; 114 private Button mClipartRadio; 115 private Button mTextRadio; 116 private Button mPickImageButton; 117 private Button mTrimCheckBox; 118 private Slider mPaddingSlider; 119 private Label mPercentLabel; 120 private Button mCropRadio; 121 private Button mCenterRadio; 122 private Button mNoShapeRadio; 123 private Button mSquareRadio; 124 private Button mCircleButton; 125 private Button mBgButton; 126 private Button mFgButton; 127 private Composite mPreviewArea; 128 private Button mFontButton; 129 private Composite mForegroundArea; 130 private Composite mImageForm; 131 private Composite mClipartForm; 132 private Composite mTextForm; 133 private Text mImagePathText; 134 135 private boolean mTimerPending; 136 private RGB mBgColor; 137 private RGB mFgColor; 138 private Text mText; 139 140 /** Most recently set image path: preserved across wizard sessions */ 141 private static String sImagePath; 142 private Button mChooseClipart; 143 private Composite mClipartPreviewPanel; 144 private Label mThemeLabel; 145 private Composite mThemeComposite; 146 private Button mHoloLightRadio; 147 private Button mHoloDarkRadio; 148 private Label mScalingLabel; 149 private Composite mScalingComposite; 150 private Label mShapeLabel; 151 private Composite mShapeComposite; 152 private Label mBgColorLabel; 153 private Label mFgColorLabel; 154 155 private boolean mIgnore; 156 private SourceType mShowingType; 157 158 /** 159 * Create the wizard. 160 * 161 * @param values the wizard state 162 */ ConfigureAssetSetPage(CreateAssetSetWizardState values)163 public ConfigureAssetSetPage(CreateAssetSetWizardState values) { 164 super("configureAssetPage"); 165 mValues = values; 166 167 setTitle("Configure Icon Set"); 168 setDescription("Configure the attributes of the icon set"); 169 } 170 171 /** 172 * Create contents of the wizard. 173 * 174 * @param parent the parent widget 175 */ 176 @Override 177 @SuppressWarnings("unused") // Don't warn about unassigned "new Label(.)": has side-effect createControl(Composite parent)178 public void createControl(Composite parent) { 179 Composite container = new Composite(parent, SWT.NULL); 180 181 setControl(container); 182 GridLayout glContainer = new GridLayout(2, false); 183 glContainer.marginWidth = 0; 184 glContainer.horizontalSpacing = 0; 185 glContainer.marginHeight = 0; 186 glContainer.verticalSpacing = 0; 187 container.setLayout(glContainer); 188 189 ScrolledComposite configurationScrollArea = new ScrolledComposite(container, SWT.V_SCROLL); 190 configurationScrollArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 2)); 191 configurationScrollArea.setExpandHorizontal(true); 192 configurationScrollArea.setExpandVertical(true); 193 194 mConfigurationArea = new Composite(configurationScrollArea, SWT.NONE); 195 GridLayout glConfigurationArea = new GridLayout(3, false); 196 glConfigurationArea.horizontalSpacing = 0; 197 glConfigurationArea.marginRight = 15; 198 glConfigurationArea.marginWidth = 0; 199 glConfigurationArea.marginHeight = 0; 200 mConfigurationArea.setLayout(glConfigurationArea); 201 202 Label foregroundLabel = new Label(mConfigurationArea, SWT.NONE); 203 foregroundLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 204 foregroundLabel.setText("Foreground:"); 205 206 Composite foregroundComposite = new Composite(mConfigurationArea, SWT.NONE); 207 foregroundComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1)); 208 GridLayout glForegroundComposite = new GridLayout(5, false); 209 glForegroundComposite.horizontalSpacing = 0; 210 foregroundComposite.setLayout(glForegroundComposite); 211 212 mImageRadio = new Button(foregroundComposite, SWT.FLAT | SWT.TOGGLE); 213 mImageRadio.setSelection(false); 214 mImageRadio.addSelectionListener(this); 215 mImageRadio.setText("Image"); 216 217 mClipartRadio = new Button(foregroundComposite, SWT.FLAT | SWT.TOGGLE); 218 mClipartRadio.setText("Clipart"); 219 mClipartRadio.addSelectionListener(this); 220 221 mTextRadio = new Button(foregroundComposite, SWT.FLAT | SWT.TOGGLE); 222 mTextRadio.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 3, 1)); 223 mTextRadio.setText("Text"); 224 mTextRadio.addSelectionListener(this); 225 new Label(mConfigurationArea, SWT.NONE); 226 227 mForegroundArea = new Composite(mConfigurationArea, SWT.NONE); 228 mForegroundArea.setLayout(new StackLayout()); 229 mForegroundArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); 230 231 mImageForm = new Composite(mForegroundArea, SWT.NONE); 232 mImageForm.setLayout(new GridLayout(3, false)); 233 234 Label fileLabel = new Label(mImageForm, SWT.NONE); 235 fileLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 236 fileLabel.setText("Image File:"); 237 238 mImagePathText = new Text(mImageForm, SWT.BORDER); 239 GridData pathLayoutData = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1); 240 pathLayoutData.widthHint = 200; 241 mImagePathText.setLayoutData(pathLayoutData); 242 mImagePathText.addSelectionListener(this); 243 mImagePathText.addModifyListener(this); 244 245 mPickImageButton = new Button(mImageForm, SWT.FLAT); 246 mPickImageButton.setText("Browse..."); 247 mPickImageButton.addSelectionListener(this); 248 249 mClipartForm = new Composite(mForegroundArea, SWT.NONE); 250 mClipartForm.setLayout(new GridLayout(2, false)); 251 252 mChooseClipart = new Button(mClipartForm, SWT.FLAT); 253 mChooseClipart.setText("Choose..."); 254 mChooseClipart.addSelectionListener(this); 255 256 mClipartPreviewPanel = new Composite(mClipartForm, SWT.NONE); 257 RowLayout rlClipartPreviewPanel = new RowLayout(SWT.HORIZONTAL); 258 rlClipartPreviewPanel.marginBottom = 0; 259 rlClipartPreviewPanel.marginTop = 0; 260 rlClipartPreviewPanel.center = true; 261 mClipartPreviewPanel.setLayout(rlClipartPreviewPanel); 262 mClipartPreviewPanel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); 263 264 mTextForm = new Composite(mForegroundArea, SWT.NONE); 265 mTextForm.setLayout(new GridLayout(2, false)); 266 267 Label textLabel = new Label(mTextForm, SWT.NONE); 268 textLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 269 textLabel.setText("Text:"); 270 271 mText = new Text(mTextForm, SWT.BORDER); 272 mText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); 273 mText.addModifyListener(this); 274 275 Label fontLabel = new Label(mTextForm, SWT.NONE); 276 fontLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 277 fontLabel.setText("Font:"); 278 279 mFontButton = new Button(mTextForm, SWT.FLAT); 280 mFontButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1)); 281 mFontButton.addSelectionListener(this); 282 mFontButton.setText("Choose Font..."); 283 new Label(mConfigurationArea, SWT.NONE); 284 285 mTrimCheckBox = new Button(mConfigurationArea, SWT.CHECK); 286 mTrimCheckBox.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); 287 mTrimCheckBox.setSelection(false); 288 mTrimCheckBox.setText("Trim Surrounding Blank Space"); 289 mTrimCheckBox.addSelectionListener(this); 290 new Label(mConfigurationArea, SWT.NONE); 291 292 Label paddingLabel = new Label(mConfigurationArea, SWT.NONE); 293 paddingLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); 294 paddingLabel.setText("Additional Padding:"); 295 new Label(mConfigurationArea, SWT.NONE); 296 297 mPaddingSlider = new Slider(mConfigurationArea, SWT.NONE); 298 mPaddingSlider.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); 299 // This doesn't work right -- not sure why. For now just use a plain slider 300 // and subtract 10 from it to get the real range. 301 //mPaddingSlider.setValues(0, -10, 50, 0, 1, 10); 302 //mPaddingSlider.setSelection(10 + 15); 303 mPaddingSlider.addSelectionListener(this); 304 305 mPercentLabel = new Label(mConfigurationArea, SWT.NONE); 306 mPercentLabel.setText(" 15%"); // Enough available space for -10% 307 mScalingLabel = new Label(mConfigurationArea, SWT.NONE); 308 mScalingLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 309 mScalingLabel.setText("Foreground Scaling:"); 310 311 mScalingComposite = new Composite(mConfigurationArea, SWT.NONE); 312 mScalingComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1)); 313 GridLayout gl_mScalingComposite = new GridLayout(5, false); 314 gl_mScalingComposite.horizontalSpacing = 0; 315 mScalingComposite.setLayout(gl_mScalingComposite); 316 317 mCropRadio = new Button(mScalingComposite, SWT.FLAT | SWT.TOGGLE); 318 mCropRadio.setSelection(true); 319 mCropRadio.setText("Crop"); 320 mCropRadio.addSelectionListener(this); 321 322 mCenterRadio = new Button(mScalingComposite, SWT.FLAT | SWT.TOGGLE); 323 mCenterRadio.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); 324 mCenterRadio.setText("Center"); 325 mCenterRadio.addSelectionListener(this); 326 327 mShapeLabel = new Label(mConfigurationArea, SWT.NONE); 328 mShapeLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 329 mShapeLabel.setText("Shape"); 330 331 mShapeComposite = new Composite(mConfigurationArea, SWT.NONE); 332 mShapeComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1)); 333 GridLayout gl_mShapeComposite = new GridLayout(6, false); 334 gl_mShapeComposite.horizontalSpacing = 0; 335 mShapeComposite.setLayout(gl_mShapeComposite); 336 337 mNoShapeRadio = new Button(mShapeComposite, SWT.FLAT | SWT.TOGGLE); 338 mNoShapeRadio.setText("None"); 339 mNoShapeRadio.addSelectionListener(this); 340 341 mSquareRadio = new Button(mShapeComposite, SWT.FLAT | SWT.TOGGLE); 342 mSquareRadio.setSelection(true); 343 mSquareRadio.setText("Square"); 344 mSquareRadio.addSelectionListener(this); 345 346 mCircleButton = new Button(mShapeComposite, SWT.FLAT | SWT.TOGGLE); 347 mCircleButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 4, 1)); 348 mCircleButton.setText("Circle"); 349 mCircleButton.addSelectionListener(this); 350 351 mThemeLabel = new Label(mConfigurationArea, SWT.NONE); 352 mThemeLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 353 mThemeLabel.setText("Theme"); 354 355 mThemeComposite = new Composite(mConfigurationArea, SWT.NONE); 356 mThemeComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); 357 GridLayout gl_mThemeComposite = new GridLayout(2, false); 358 gl_mThemeComposite.horizontalSpacing = 0; 359 mThemeComposite.setLayout(gl_mThemeComposite); 360 361 mHoloLightRadio = new Button(mThemeComposite, SWT.FLAT | SWT.TOGGLE); 362 mHoloLightRadio.setText("Holo Light"); 363 mHoloLightRadio.setSelection(true); 364 mHoloLightRadio.addSelectionListener(this); 365 366 mHoloDarkRadio = new Button(mThemeComposite, SWT.FLAT | SWT.TOGGLE); 367 mHoloDarkRadio.setText("Holo Dark"); 368 mHoloDarkRadio.addSelectionListener(this); 369 370 mBgColorLabel = new Label(mConfigurationArea, SWT.NONE); 371 mBgColorLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 372 mBgColorLabel.setText("Background Color:"); 373 374 mBgButton = new Button(mConfigurationArea, SWT.FLAT); 375 mBgButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); 376 mBgButton.addSelectionListener(this); 377 mBgButton.setAlignment(SWT.CENTER); 378 379 mFgColorLabel = new Label(mConfigurationArea, SWT.NONE); 380 mFgColorLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); 381 mFgColorLabel.setText("Foreground Color:"); 382 383 mFgButton = new Button(mConfigurationArea, SWT.FLAT); 384 mFgButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); 385 mFgButton.setAlignment(SWT.CENTER); 386 mFgButton.addSelectionListener(this); 387 388 configurationScrollArea.setContent(mConfigurationArea); 389 configurationScrollArea.setMinSize(mConfigurationArea.computeSize(SWT.DEFAULT, 390 SWT.DEFAULT)); 391 392 Label previewLabel = new Label(container, SWT.NONE); 393 previewLabel.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1)); 394 previewLabel.setText("Preview:"); 395 396 mPreviewArea = new Composite(container, SWT.BORDER); 397 398 RowLayout rlPreviewAreaPreviewArea = new RowLayout(SWT.HORIZONTAL); 399 rlPreviewAreaPreviewArea.wrap = true; 400 rlPreviewAreaPreviewArea.pack = true; 401 rlPreviewAreaPreviewArea.center = true; 402 rlPreviewAreaPreviewArea.spacing = 0; 403 rlPreviewAreaPreviewArea.marginBottom = 0; 404 rlPreviewAreaPreviewArea.marginTop = 0; 405 rlPreviewAreaPreviewArea.marginRight = 0; 406 rlPreviewAreaPreviewArea.marginLeft = 0; 407 mPreviewArea.setLayout(rlPreviewAreaPreviewArea); 408 GridData gdMPreviewArea = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1); 409 gdMPreviewArea.widthHint = PREVIEW_AREA_WIDTH; 410 mPreviewArea.setLayoutData(gdMPreviewArea); 411 412 // Initial color 413 Display display = parent.getDisplay(); 414 updateColor(display, mValues.background, true /*background*/); 415 updateColor(display, mValues.foreground, false /*background*/); 416 417 setSourceType(mValues.sourceType); 418 419 new Label(mConfigurationArea, SWT.NONE); 420 new Label(mConfigurationArea, SWT.NONE); 421 new Label(mConfigurationArea, SWT.NONE); 422 423 validatePage(); 424 } 425 configureAssetType(AssetType type)426 void configureAssetType(AssetType type) { 427 if (mValues.sourceType != mShowingType) { 428 mShowingType = mValues.sourceType; 429 showGroup(type.needsForegroundScaling(), mScalingLabel, mScalingComposite); 430 showGroup(type.needsShape(), mShapeLabel, mShapeComposite); 431 showGroup(type.needsTheme(), mThemeLabel, mThemeComposite); 432 showGroup(type.needsColors(), mBgColorLabel, mBgButton); 433 showGroup(type.needsColors() && mValues.sourceType != SourceType.IMAGE, 434 mFgColorLabel, mFgButton); 435 436 Composite parent = mScalingLabel.getParent(); 437 parent.pack(); 438 parent.layout(); 439 } 440 } 441 showGroup(boolean show, Control control1, Control control2)442 private static void showGroup(boolean show, Control control1, Control control2) { 443 showControl(show, control1); 444 showControl(show, control2); 445 } 446 showControl(boolean show, Control control)447 private static void showControl(boolean show, Control control) { 448 Object data = control.getLayoutData(); 449 if (data instanceof GridData) { 450 GridData gridData = (GridData) data; 451 gridData.exclude = !show; 452 } 453 control.setVisible(show); 454 } 455 456 @Override setVisible(boolean visible)457 public void setVisible(boolean visible) { 458 super.setVisible(visible); 459 460 // We update the image selection here rather than in {@link #createControl} because 461 // that method is called when the wizard is created, and we want to wait until the 462 // user has chosen a project before attempting to look up the right default image to use 463 if (visible) { 464 mShown = true; 465 466 // Clear out old previews - important if the user goes back to page one, changes 467 // asset type and steps into page 2 - at that point we arrive here and we might 468 // display the old previews for a brief period until the preview delay timer expires. 469 for (Control c : mPreviewArea.getChildren()) { 470 c.dispose(); 471 } 472 mPreviewArea.layout(true); 473 474 // Update asset type configuration: will show/hide parameter controls depending 475 // on which asset type is chosen 476 AssetType type = mValues.type; 477 assert type != null; 478 configureAssetType(type); 479 480 // Initial image - use the most recently used image, or the default launcher 481 // icon created in our default projects, if there 482 if (mValues.imagePath != null) { 483 sImagePath = mValues.imagePath.getPath(); 484 } 485 if (sImagePath == null) { 486 IProject project = mValues.project; 487 if (project != null) { 488 IResource icon = project.findMember("res/drawable-hdpi/icon.png"); //$NON-NLS-1$ 489 if (icon != null) { 490 IWorkspaceRoot workspace = ResourcesPlugin.getWorkspace().getRoot(); 491 IPath workspacePath = workspace.getLocation(); 492 sImagePath = workspacePath.append(icon.getFullPath()).toOSString(); 493 } 494 } 495 } 496 if (sImagePath != null) { 497 mValues.imagePath = new File(sImagePath); 498 mImagePathText.setText(sImagePath); 499 } 500 501 try { 502 mIgnore = true; 503 504 mTrimCheckBox.setSelection(mValues.trim); 505 506 // This doesn't work right -- not sure why. For now just use a plain slider 507 // and subtract 10 from it to get the real range. 508 //mPaddingSlider.setValues(0, -10, 50, 0, 1, 10); 509 //mPaddingSlider.setSelection(10 + 15); 510 mPaddingSlider.setSelection(mValues.padding + 10); 511 mPercentLabel.setText(Integer.toString(mValues.padding) + '%'); 512 513 if (mValues.imagePath != null) { 514 mImagePathText.setText(mValues.imagePath.getPath()); 515 } 516 517 if (mValues.text != null) { 518 mText.setText(mValues.text); 519 } 520 521 setSourceType(mValues.sourceType); 522 523 // Shape=NONE does not apply for notification icons; it's needed for API < 9 524 if (mValues.shape == Shape.NONE && mValues.type == AssetType.NOTIFICATION) { 525 mValues.shape = Shape.SQUARE; 526 } 527 528 setShape(mValues.shape); 529 mNoShapeRadio.setEnabled(mValues.type != AssetType.NOTIFICATION); 530 531 if (mValues.sourceType == SourceType.CLIPART 532 && mValues.clipartName != null) { 533 updateClipartPreview(); 534 } 535 536 // Initial color 537 Display display = mPreviewArea.getDisplay(); 538 //updateColor(display, new RGB(0xa4, 0xc6, 0x39), true /*background*/); 539 updateColor(display, mValues.background, true /*background*/); 540 updateColor(display, mValues.foreground, false /*background*/); 541 542 updateTrimOptions(); 543 } finally { 544 mIgnore = false; 545 } 546 547 validatePage(); 548 549 requestUpdatePreview(true /*quickly*/); 550 551 if (mTextRadio.getSelection()) { 552 mText.setFocus(); 553 } 554 } 555 } 556 setSourceType(CreateAssetSetWizardState.SourceType sourceType)557 private void setSourceType(CreateAssetSetWizardState.SourceType sourceType) { 558 if (sourceType == CreateAssetSetWizardState.SourceType.IMAGE) { 559 chooseForegroundTab(mImageRadio, mImageForm); 560 } else if (sourceType == CreateAssetSetWizardState.SourceType.CLIPART) { 561 chooseForegroundTab(mClipartRadio, mClipartForm); 562 mChooseClipart.setFocus(); 563 } else if (sourceType == CreateAssetSetWizardState.SourceType.TEXT) { 564 updateFontLabel(); 565 chooseForegroundTab(mTextRadio, mTextForm); 566 mText.setFocus(); 567 } 568 } 569 updateTrimOptions()570 private void updateTrimOptions() { 571 // Trimming and padding is not available for clipart images; padding etc is 572 // predefined to work well with action bar icons 573 if (mValues.sourceType == SourceType.CLIPART 574 && mValues.type == AssetType.ACTIONBAR) { 575 mTrimCheckBox.setEnabled(false); 576 mPaddingSlider.setEnabled(false); 577 mValues.trim = false; 578 } else if (!mTrimCheckBox.isEnabled()) { 579 mTrimCheckBox.setEnabled(true); 580 mPaddingSlider.setEnabled(true); 581 } 582 } 583 validatePage()584 private boolean validatePage() { 585 String error = null; 586 //String warning = null; 587 588 if (mImageRadio.getSelection()) { 589 String path = mValues.imagePath != null ? mValues.imagePath.getPath() : null; 590 if (path == null || path.length() == 0) { 591 error = "Select an image"; 592 } else if (path.equals(DEFAULT_LAUNCHER_ICON)) { 593 // Silent 594 } else if (!(new File(path).exists())) { 595 error = String.format("%1$s does not exist", path); 596 } else { 597 // Preserve across wizard sessions 598 sImagePath = path; 599 } 600 } else if (mTextRadio.getSelection()) { 601 if (mValues.text.length() == 0) { 602 error = "Enter text"; 603 } 604 } else { 605 assert mClipartRadio.getSelection(); 606 if (mValues.clipartName == null) { 607 error = "Select clip art"; 608 } 609 } 610 611 setPageComplete(error == null); 612 if (error != null) { 613 setMessage(error, IMessageProvider.ERROR); 614 //} else if (warning != null) { 615 // setMessage(warning, IMessageProvider.WARNING); 616 } else { 617 setErrorMessage(null); 618 setMessage(null); 619 } 620 621 return error == null; 622 } 623 624 @Override isPageComplete()625 public boolean isPageComplete() { 626 // Force user to reach second page before hitting Finish 627 return mShown; 628 } 629 630 // ---- Implements ModifyListener ---- 631 632 @Override modifyText(ModifyEvent e)633 public void modifyText(ModifyEvent e) { 634 if (mIgnore) { 635 return; 636 } 637 638 if (e.getSource() == mImagePathText) { 639 mValues.imagePath = new File(mImagePathText.getText().trim()); 640 requestUpdatePreview(false); 641 } else if (e.getSource() == mText) { 642 mValues.text = mText.getText().trim(); 643 requestUpdatePreview(false); 644 } 645 646 validatePage(); 647 } 648 649 // ---- Implements SelectionListener ---- 650 651 @Override widgetDefaultSelected(SelectionEvent e)652 public void widgetDefaultSelected(SelectionEvent e) { 653 // Nothing to do 654 } 655 656 @Override widgetSelected(SelectionEvent e)657 public void widgetSelected(SelectionEvent e) { 658 if (mIgnore) { 659 return; 660 } 661 662 Object source = e.getSource(); 663 boolean updateQuickly = true; 664 665 // Tabs 666 if (source == mImageRadio) { 667 mValues.sourceType = CreateAssetSetWizardState.SourceType.IMAGE; 668 chooseForegroundTab((Button) source, mImageForm); 669 configureAssetType(mValues.type); 670 updateTrimOptions(); 671 } else if (source == mClipartRadio) { 672 mValues.sourceType = CreateAssetSetWizardState.SourceType.CLIPART; 673 chooseForegroundTab((Button) source, mClipartForm); 674 configureAssetType(mValues.type); 675 updateTrimOptions(); 676 } else if (source == mTextRadio) { 677 mValues.sourceType = CreateAssetSetWizardState.SourceType.TEXT; 678 updateFontLabel(); 679 chooseForegroundTab((Button) source, mTextForm); 680 configureAssetType(mValues.type); 681 mText.setFocus(); 682 updateTrimOptions(); 683 } 684 685 // Choose image file 686 if (source == mPickImageButton) { 687 FileDialog dialog = new FileDialog(mPickImageButton.getShell(), SWT.OPEN); 688 689 String curLocation = mImagePathText.getText().trim(); 690 if (!curLocation.isEmpty()) { 691 dialog.setFilterPath(curLocation); 692 } 693 694 String file = dialog.open(); 695 if (file != null) { 696 mValues.imagePath = new File(file); 697 mImagePathText.setText(file); 698 } 699 } 700 701 // Enforce Radio Groups 702 if (source == mCropRadio) { 703 mCropRadio.setSelection(true); // Ensure that you can't toggle it off 704 mCenterRadio.setSelection(false); 705 mValues.crop = true; 706 } else if (source == mCenterRadio) { 707 mCenterRadio.setSelection(true); 708 mCropRadio.setSelection(false); 709 mValues.crop = false; 710 } 711 if (source == mSquareRadio) { 712 mValues.shape = GraphicGenerator.Shape.SQUARE; 713 setShape(mValues.shape); 714 } else if (source == mCircleButton) { 715 mValues.shape = GraphicGenerator.Shape.CIRCLE; 716 setShape(mValues.shape); 717 } else if (source == mNoShapeRadio) { 718 mValues.shape = GraphicGenerator.Shape.NONE; 719 setShape(mValues.shape); 720 } 721 722 if (source == mTrimCheckBox) { 723 mValues.trim = mTrimCheckBox.getSelection(); 724 } 725 726 if (source == mHoloDarkRadio) { 727 mHoloDarkRadio.setSelection(true); 728 mHoloLightRadio.setSelection(false); 729 mValues.holoDark = true; 730 } else if (source == mHoloLightRadio) { 731 mHoloLightRadio.setSelection(true); 732 mHoloDarkRadio.setSelection(false); 733 mValues.holoDark = false; 734 } 735 736 if (source == mChooseClipart) { 737 MessageDialog dialog = new MessageDialog(mChooseClipart.getShell(), 738 "Choose Clip Art", 739 null, "Choose Clip Art Image:", MessageDialog.NONE, 740 new String[] { "Close" }, 0) { 741 @Override 742 protected Control createCustomArea(Composite parent) { 743 // Outer form which just establishes a width for the inner form which 744 // wraps in a RowLayout 745 Composite outer = new Composite(parent, SWT.NONE); 746 GridLayout gridLayout = new GridLayout(); 747 outer.setLayout(gridLayout); 748 749 Composite chooserForm = new Composite(outer, SWT.NONE); 750 GridData gd = new GridData(); 751 gd.grabExcessVerticalSpace = true; 752 gd.widthHint = 450; 753 chooserForm.setLayoutData(gd); 754 RowLayout clipartFormLayout = new RowLayout(SWT.HORIZONTAL); 755 clipartFormLayout.center = true; 756 clipartFormLayout.wrap = true; 757 chooserForm.setLayout(clipartFormLayout); 758 759 MouseAdapter clickListener = new MouseAdapter() { 760 @Override 761 public void mouseDown(MouseEvent event) { 762 // Clicked on some of the sample art 763 if (event.widget instanceof ImageControl) { 764 ImageControl image = (ImageControl) event.widget; 765 mValues.clipartName = (String) image.getData(); 766 close(); 767 768 updateClipartPreview(); 769 updatePreview(); 770 } 771 } 772 }; 773 Display display = chooserForm.getDisplay(); 774 Color hoverColor = display.getSystemColor(SWT.COLOR_RED); 775 Iterator<String> clipartImages = GraphicGenerator.getClipartNames(); 776 while (clipartImages.hasNext()) { 777 String name = clipartImages.next(); 778 try { 779 BufferedImage icon = GraphicGenerator.getClipartIcon(name); 780 if (icon != null) { 781 Image swtImage = SwtUtils.convertToSwt(display, icon, true, -1); 782 ImageControl img = new ImageControl(chooserForm, 783 SWT.NONE, swtImage); 784 img.setData(name); 785 img.setHoverColor(hoverColor); 786 img.addMouseListener(clickListener); 787 } 788 } catch (IOException e1) { 789 AdtPlugin.log(e1, null); 790 } 791 } 792 outer.pack(); 793 outer.layout(); 794 return outer; 795 } 796 }; 797 dialog.open(); 798 } 799 800 if (source == mBgButton) { 801 ColorDialog dlg = new ColorDialog(mBgButton.getShell()); 802 dlg.setRGB(mBgColor); 803 dlg.setText("Choose a new Background Color"); 804 RGB rgb = dlg.open(); 805 if (rgb != null) { 806 // Dispose the old color, create the 807 // new one, and set into the label 808 mValues.background = rgb; 809 updateColor(mBgButton.getDisplay(), rgb, true /*background*/); 810 } 811 } else if (source == mFgButton) { 812 ColorDialog dlg = new ColorDialog(mFgButton.getShell()); 813 dlg.setRGB(mFgColor); 814 dlg.setText("Choose a new Foreground Color"); 815 RGB rgb = dlg.open(); 816 if (rgb != null) { 817 // Dispose the old color, create the 818 // new one, and set into the label 819 mValues.foreground = rgb; 820 updateColor(mFgButton.getDisplay(), rgb, false /*background*/); 821 } 822 } 823 824 if (source == mFontButton) { 825 FontDialog dialog = new FontDialog(mFontButton.getShell()); 826 FontData[] fontList; 827 if (mFontButton.getData() == null) { 828 fontList = mFontButton.getDisplay().getFontList( 829 mValues.getTextFont().getFontName(), true /*scalable*/); 830 } else { 831 fontList = mFontButton.getFont().getFontData(); 832 } 833 dialog.setFontList(fontList); 834 FontData data = dialog.open(); 835 if (data != null) { 836 Font font = new Font(mFontButton.getDisplay(), dialog.getFontList()); 837 mFontButton.setFont(font); 838 mFontButton.setData(font); 839 840 // Always use a large font for the rendering, even though user is typically 841 // picking small font sizes in the font chooser 842 //int dpi = mFontButton.getDisplay().getDPI().y; 843 //int height = (int) Math.round(fontData.getHeight() * dpi / 72.0); 844 int fontHeight = new TextRenderUtil.Options().fontSize; 845 FontData fontData = font.getFontData()[0]; 846 int awtStyle = java.awt.Font.PLAIN; 847 int swtStyle = fontData.getStyle(); 848 if ((swtStyle & SWT.ITALIC) != 0) { 849 awtStyle |= java.awt.Font.ITALIC; 850 } 851 if ((swtStyle & SWT.BOLD) != 0) { 852 awtStyle = java.awt.Font.BOLD; 853 } 854 mValues.setTextFont(new java.awt.Font(fontData.getName(), awtStyle, fontHeight)); 855 856 updateFontLabel(); 857 mFontButton.getParent().pack(); 858 } 859 } 860 861 if (source == mPaddingSlider) { 862 mValues.padding = getPadding(); 863 mPercentLabel.setText(Integer.toString(getPadding()) + '%'); 864 865 // When dragging the slider, only do periodic updates 866 updateQuickly = false; 867 } 868 869 requestUpdatePreview(updateQuickly); 870 } 871 872 @SuppressWarnings("unused") // SWT constructors have side effects and are not unused updateClipartPreview()873 private void updateClipartPreview() { 874 for (Control c : mClipartPreviewPanel.getChildren()) { 875 c.dispose(); 876 } 877 if (mClipartPreviewPanel.getChildren().length == 0) { 878 try { 879 BufferedImage icon = GraphicGenerator.getClipartIcon( 880 mValues.clipartName); 881 if (icon != null) { 882 Display display = mClipartForm.getDisplay(); 883 Image swtImage = SwtUtils.convertToSwt(display, icon, 884 true, -1); 885 new ImageControl(mClipartPreviewPanel, 886 SWT.NONE, swtImage); 887 } 888 } catch (IOException e1) { 889 AdtPlugin.log(e1, null); 890 } 891 mClipartPreviewPanel.pack(); 892 mClipartPreviewPanel.layout(); 893 } 894 } 895 setShape(GraphicGenerator.Shape shape)896 private void setShape(GraphicGenerator.Shape shape) { 897 if (shape == GraphicGenerator.Shape.SQUARE) { 898 mSquareRadio.setSelection(true); 899 mCircleButton.setSelection(false); 900 mNoShapeRadio.setSelection(false); 901 } else if (shape == GraphicGenerator.Shape.CIRCLE) { 902 mCircleButton.setSelection(true); 903 mSquareRadio.setSelection(false); 904 mNoShapeRadio.setSelection(false); 905 } else if (shape == GraphicGenerator.Shape.NONE) { 906 mNoShapeRadio.setSelection(true); 907 mCircleButton.setSelection(false); 908 mSquareRadio.setSelection(false); 909 } else { 910 assert false : shape; 911 } 912 } 913 updateFontLabel()914 private void updateFontLabel() { 915 mFontButton.setText(mValues.getTextFont().getFontName()); 916 } 917 getPadding()918 private int getPadding() { 919 // Shifted - see comment for mPaddingSlider construction for an explanation 920 return mPaddingSlider.getSelection() - 10; 921 } 922 chooseForegroundTab(Button newButton, Composite newArea)923 private void chooseForegroundTab(Button newButton, Composite newArea) { 924 if (newButton.getSelection()) { 925 mImageRadio.setSelection(false); 926 mClipartRadio.setSelection(false); 927 mTextRadio.setSelection(false); 928 newButton.setSelection(true); 929 StackLayout stackLayout = (StackLayout) mForegroundArea.getLayout(); 930 stackLayout.topControl = newArea; 931 mForegroundArea.layout(); 932 } else { 933 // Treat it as a radio button: you can't click to turn it off, you have to 934 // click on one of the other buttons 935 newButton.setSelection(true); 936 } 937 } 938 939 /** 940 * Delay updates of the preview, to ensure that the SWT UI acts immediately (to handle 941 * radio group selections etc). 942 * 943 * @param quickly if true, update the previews soon, otherwise schedule one a bit later 944 */ requestUpdatePreview(boolean quickly)945 private void requestUpdatePreview(boolean quickly) { 946 if (mTimerPending) { 947 return; 948 } 949 mTimerPending = true; 950 951 final Runnable timer = new Runnable() { 952 @Override 953 public void run() { 954 mTimerPending = false; 955 updatePreview(); 956 } 957 }; 958 959 mPreviewArea.getDisplay().timerExec(quickly ? 10 : 250, timer); 960 } 961 updatePreview()962 private void updatePreview() { 963 Display display = mPreviewArea.getDisplay(); 964 965 for (Control c : mPreviewArea.getChildren()) { 966 c.dispose(); 967 } 968 969 if (!validatePage()) { 970 return; 971 } 972 973 Map<String, Map<String, BufferedImage>> map = generateImages(mValues, 974 true /*previewOnly*/, this); 975 for (Entry<String, Map<String, BufferedImage>> categoryEntry : map.entrySet()) { 976 String category = categoryEntry.getKey(); 977 if (category.length() > 0) { 978 Label nameLabel = new Label(mPreviewArea, SWT.NONE); 979 nameLabel.setText(String.format("%1$s:", category)); 980 RowData rowData = new RowData(); 981 nameLabel.setLayoutData(rowData); 982 // Ensure these get their own rows 983 rowData.width = PREVIEW_AREA_WIDTH; 984 } 985 986 Map<String, BufferedImage> images = categoryEntry.getValue(); 987 for (Entry<String, BufferedImage> entry : images.entrySet()) { 988 BufferedImage image = entry.getValue(); 989 Image swtImage = SwtUtils.convertToSwt(display, image, true, -1); 990 if (swtImage != null) { 991 @SuppressWarnings("unused") // Has side effect 992 ImageControl imageControl = new ImageControl(mPreviewArea, SWT.NONE, swtImage); 993 } 994 } 995 } 996 997 mPreviewArea.layout(true); 998 } 999 1000 /** 1001 * Generate images using the given wizard state 1002 * 1003 * @param mValues the state to use 1004 * @param previewOnly whether we are only generating previews 1005 * @param page if non null, a wizard page to write error messages to 1006 * @return a map of image objects 1007 */ generateImages( @onNull CreateAssetSetWizardState mValues, boolean previewOnly, @Nullable WizardPage page)1008 public static Map<String, Map<String, BufferedImage>> generateImages( 1009 @NonNull CreateAssetSetWizardState mValues, 1010 boolean previewOnly, 1011 @Nullable WizardPage page) { 1012 // Map of ids to images: Preserve insertion order (the densities) 1013 Map<String, Map<String, BufferedImage>> categoryMap = 1014 new LinkedHashMap<String, Map<String, BufferedImage>>(); 1015 1016 AssetType type = mValues.type; 1017 boolean trim = mValues.trim; 1018 1019 BufferedImage sourceImage = null; 1020 switch (mValues.sourceType) { 1021 case IMAGE: { 1022 // Load the image 1023 // TODO: Only do this when the source image type is image 1024 String path = mValues.imagePath != null ? mValues.imagePath.getPath() : ""; 1025 if (path.length() == 0) { 1026 if (page != null) { 1027 page.setErrorMessage("Enter a filename"); 1028 } 1029 return Collections.emptyMap(); 1030 } 1031 if (!path.equals(DEFAULT_LAUNCHER_ICON)) { 1032 File file = new File(path); 1033 if (!file.isFile()) { 1034 if (page != null) { 1035 page.setErrorMessage(String.format("%1$s does not exist", file.getPath())); 1036 } 1037 return Collections.emptyMap(); 1038 } 1039 } 1040 1041 if (page != null) { 1042 page.setErrorMessage(null); 1043 } 1044 try { 1045 sourceImage = mValues.getCachedImage(path, false); 1046 if (sourceImage != null) { 1047 if (trim) { 1048 sourceImage = ImageUtils.cropBlank(sourceImage, null, TYPE_INT_ARGB); 1049 } 1050 if (mValues.padding != 0) { 1051 sourceImage = Util.paddedImage(sourceImage, mValues.padding); 1052 } 1053 } 1054 } catch (IOException ioe) { 1055 if (page != null) { 1056 page.setErrorMessage(ioe.getLocalizedMessage()); 1057 } 1058 } 1059 break; 1060 } 1061 case CLIPART: { 1062 try { 1063 sourceImage = GraphicGenerator.getClipartImage(mValues.clipartName); 1064 1065 boolean isActionBar = mValues.type == AssetType.ACTIONBAR; 1066 if (trim && !isActionBar) { 1067 sourceImage = ImageUtils.cropBlank(sourceImage, null, TYPE_INT_ARGB); 1068 } 1069 1070 if (type.needsColors()) { 1071 RGB fg = mValues.foreground; 1072 int color = 0xFF000000 | (fg.red << 16) | (fg.green << 8) | fg.blue; 1073 Paint paint = new java.awt.Color(color); 1074 sourceImage = Util.filledImage(sourceImage, paint); 1075 } 1076 1077 int padding = mValues.padding; 1078 if (padding != 0 && !isActionBar) { 1079 sourceImage = Util.paddedImage(sourceImage, padding); 1080 } 1081 } catch (IOException e) { 1082 AdtPlugin.log(e, null); 1083 return categoryMap; 1084 } 1085 break; 1086 } 1087 case TEXT: { 1088 String text = mValues.text; 1089 TextRenderUtil.Options options = new TextRenderUtil.Options(); 1090 options.font = mValues.getTextFont(); 1091 int color; 1092 if (type.needsColors()) { 1093 RGB fg = mValues.foreground; 1094 color = 0xFF000000 | (fg.red << 16) | (fg.green << 8) | fg.blue; 1095 } else { 1096 color = 0xFFFFFFFF; 1097 } 1098 options.foregroundColor = color; 1099 sourceImage = TextRenderUtil.renderTextImage(text, mValues.padding, options); 1100 1101 if (trim) { 1102 sourceImage = ImageUtils.cropBlank(sourceImage, null, TYPE_INT_ARGB); 1103 } 1104 1105 int padding = mValues.padding; 1106 if (padding != 0) { 1107 sourceImage = Util.paddedImage(sourceImage, padding); 1108 } 1109 break; 1110 } 1111 } 1112 1113 GraphicGenerator generator = null; 1114 GraphicGenerator.Options options = null; 1115 switch (type) { 1116 case LAUNCHER: { 1117 generator = new LauncherIconGenerator(); 1118 LauncherIconGenerator.LauncherOptions launcherOptions = 1119 new LauncherIconGenerator.LauncherOptions(); 1120 launcherOptions.shape = mValues.shape; 1121 launcherOptions.crop = mValues.crop; 1122 launcherOptions.style = GraphicGenerator.Style.SIMPLE; 1123 1124 RGB bg = mValues.background; 1125 int color = (bg.red << 16) | (bg.green << 8) | bg.blue; 1126 launcherOptions.backgroundColor = color; 1127 // Flag which tells the generator iterator to include a web graphic 1128 launcherOptions.isWebGraphic = !previewOnly; 1129 options = launcherOptions; 1130 1131 break; 1132 } 1133 case MENU: 1134 generator = new MenuIconGenerator(); 1135 options = new GraphicGenerator.Options(); 1136 break; 1137 case ACTIONBAR: { 1138 generator = new ActionBarIconGenerator(); 1139 ActionBarIconGenerator.ActionBarOptions actionBarOptions = 1140 new ActionBarIconGenerator.ActionBarOptions(); 1141 actionBarOptions.theme = mValues.holoDark 1142 ? ActionBarIconGenerator.Theme.HOLO_DARK 1143 : ActionBarIconGenerator.Theme.HOLO_LIGHT; 1144 actionBarOptions.sourceIsClipart = (mValues.sourceType == SourceType.CLIPART); 1145 1146 options = actionBarOptions; 1147 break; 1148 } 1149 case NOTIFICATION: { 1150 generator = new NotificationIconGenerator(); 1151 options = new NotificationIconGenerator.NotificationOptions(); 1152 break; 1153 } 1154 case TAB: 1155 generator = new TabIconGenerator(); 1156 options = new TabIconGenerator.TabOptions(); 1157 break; 1158 default: 1159 AdtPlugin.log(IStatus.ERROR, "Unsupported asset type: %1$s", type); 1160 return categoryMap; 1161 } 1162 1163 options.sourceImage = sourceImage; 1164 1165 IProject project = mValues.project; 1166 if (mValues.minSdk != -1) { 1167 options.minSdk = mValues.minSdk; 1168 } else { 1169 Pair<Integer, Integer> v = ManifestInfo.computeSdkVersions(project); 1170 options.minSdk = v.getFirst(); 1171 } 1172 1173 String baseName = mValues.outputName; 1174 generator.generate(null, categoryMap, mValues, options, baseName); 1175 1176 return categoryMap; 1177 } 1178 1179 /** 1180 * Generate custom icons into the project based on the asset studio wizard 1181 * state 1182 * 1183 * @param newProject the project to write into 1184 * @param values the wizard state to read configuration settings from 1185 * @param previewOnly whether we are only generating a preview. For example, 1186 * the launcher icons won't generate a huge 512x512 web graphic 1187 * in preview mode 1188 * @param page a wizard page to write error messages to, or null 1189 */ generateIcons(final IProject newProject, @NonNull CreateAssetSetWizardState values, boolean previewOnly, @Nullable WizardPage page)1190 public static void generateIcons(final IProject newProject, 1191 @NonNull CreateAssetSetWizardState values, 1192 boolean previewOnly, 1193 @Nullable WizardPage page) { 1194 // Generate the custom icons 1195 Map<String, Map<String, BufferedImage>> categories = generateImages(values, 1196 false /*previewOnly*/, page); 1197 for (Map<String, BufferedImage> previews : categories.values()) { 1198 for (Map.Entry<String, BufferedImage> entry : previews.entrySet()) { 1199 String relativePath = entry.getKey(); 1200 IPath dest = new Path(relativePath); 1201 IFile file = newProject.getFile(dest); 1202 1203 // In case template already created icons (should remove that) 1204 // remove them first 1205 if (file.exists()) { 1206 try { 1207 file.delete(true, new NullProgressMonitor()); 1208 } catch (CoreException e) { 1209 AdtPlugin.log(e, null); 1210 } 1211 } 1212 AdtUtils.createWsParentDirectory(file.getParent()); 1213 BufferedImage image = entry.getValue(); 1214 1215 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 1216 try { 1217 ImageIO.write(image, "PNG", stream); //$NON-NLS-1$ 1218 byte[] bytes = stream.toByteArray(); 1219 InputStream is = new ByteArrayInputStream(bytes); 1220 file.create(is, true /*force*/, null /*progress*/); 1221 } catch (IOException e) { 1222 AdtPlugin.log(e, null); 1223 } catch (CoreException e) { 1224 AdtPlugin.log(e, null); 1225 } 1226 1227 try { 1228 file.getParent().refreshLocal(1, new NullProgressMonitor()); 1229 } catch (CoreException e) { 1230 AdtPlugin.log(e, null); 1231 } 1232 } 1233 } 1234 } 1235 updateColor(Display display, RGB color, boolean isBackground)1236 private void updateColor(Display display, RGB color, boolean isBackground) { 1237 // Button.setBackgroundColor does not work (at least not on OSX) so 1238 // we instead have to use Button.setImage with an image of the given 1239 // color 1240 BufferedImage coloredImage = ImageUtils.createColoredImage(60, 20, color); 1241 Image image = SwtUtils.convertToSwt(display, coloredImage, false, -1); 1242 1243 if (isBackground) { 1244 mBgColor = color; 1245 mBgButton.setImage(image); 1246 } else { 1247 mFgColor = color; 1248 mFgButton.setImage(image); 1249 } 1250 } 1251 } 1252