in android-npw/src/com/android/tools/idea/npw/assetstudio/ui/ConfigureAdaptiveIconPanel.java [618:860]
private void initializeListenersAndBindings() {
myForegroundTrimmed = new SelectedProperty(myForegroundTrimYesRadioButton);
myBackgroundTrimmed = new SelectedProperty(myBackgroundTrimYesRadioButton);
myForegroundResizePercent = bindTwoWay(myGeneralBindings, myForegroundResizeSlider, myForegroundResizeValueTextField);
myBackgroundResizePercent = bindTwoWay(myGeneralBindings, myBackgroundResizeSlider, myBackgroundResizeValueTextField);
myForegroundColor = new ColorProperty(myForegroundColorPanel);
myBackgroundColor = ObjectProperty.wrap(new ColorProperty(myBackgroundColorPanel));
myGenerateLegacyIcon = new SelectedProperty(myGenerateLegacyIconYesRadioButton);
myGenerateRoundIcon = new SelectedProperty(myGenerateRoundIconYesRadioButton);
myGeneratePlayStoreIcon = new SelectedProperty(myGeneratePlayStoreIconYesRadioButton);
myGenerateWebpIcons = new SelectedProperty(myIconFormatWebpRadioButton);
myLegacyIconShape = ObjectProperty.wrap(new SelectedItemProperty<>(myLegacyIconShapeComboBox));
updateBindingsAndUiForActiveIconType();
// Update foreground layer asset type depending on asset type radio buttons.
myForegroundAssetType.addListener(() -> {
AssetComponent<?> assetComponent = myForegroundAssetPanelMap.get(myForegroundAssetType.get());
myForegroundActiveAsset.set(assetComponent.getAsset());
});
// Update background asset depending on asset type radio buttons.
myBackgroundAssetType.addListener(() -> {
if (myBackgroundAssetType.get() == BackgroundAssetType.IMAGE) {
myBackgroundImageAsset.setValue(myBackgroundImageAssetBrowser.getAsset());
}
else {
myBackgroundImageAsset.clear();
}
});
// If any of our underlying asset panels change, we should pass that on to anyone listening to
// us as well.
ActionListener assetPanelListener = e -> fireAssetListeners();
for (AssetComponent<?> assetComponent : myForegroundAssetPanelMap.values()) {
assetComponent.addAssetListener(assetPanelListener);
}
myBackgroundImageAssetBrowser.addAssetListener(assetPanelListener);
Runnable onAssetModified = this::fireAssetListeners;
// Property to check if the asset used for monochrome layer is resizable.
// This is used to show or hide controls based on the type of the asset.
// For example: the resize slider control.
BoolValueProperty monochromeIsResizable = new BoolValueProperty();
// Bindings for monochrome components only if monochrome is supported.
if (myIsMonochromeSupported) {
myMonochromeTrimmed = new SelectedProperty(myMonochromeTrimYesRadioButton);
myMonochromeResizePercent = bindTwoWay(myGeneralBindings, myMonochromeResizeSlider, myMonochromeResizeValueTextField);
myMonochromeColor = new ColorProperty(myMonochromeColorPanel);
// Update monochrome layer asset type depending on asset type radio buttons.
myMonochromeAssetType.addListener(() -> {
AssetComponent<?> assetComponent = myMonochromeAssetPanelMap.get(myMonochromeAssetType.get());
myMonochromeActiveAsset.setNullableValue(assetComponent.getAsset());
});
for (AssetComponent<?> assetComponent : myMonochromeAssetPanelMap.values()) {
assetComponent.addAssetListener(assetPanelListener);
}
myListeners
.listenAll(myForegroundTrimmed, myForegroundResizePercent, myForegroundColor,
myBackgroundTrimmed, myBackgroundResizePercent, myBackgroundColor,
myMonochromeTrimmed, myMonochromeResizePercent, myMonochromeColor,
myGenerateLegacyIcon, myLegacyIconShape,
myGenerateRoundIcon, myGeneratePlayStoreIcon, myGenerateWebpIcons)
.with(onAssetModified);
// Listens for changes to the controls on the foreground panel. When the asset is changed,
// it updates the controller bindings to match the properties of the new asset.
myListeners.listenAndFire(myMonochromeActiveAsset, () -> {
myMonochromeActiveAssetBindings.releaseAll();
BaseAsset asset = myMonochromeActiveAsset.getValueOrNull();
if (asset != null) {
myMonochromeActiveAssetBindings.bindTwoWay(myMonochromeTrimmed, asset.trimmed());
myMonochromeActiveAssetBindings.bindTwoWay(myMonochromeResizePercent, asset.scalingPercent());
OptionalValueProperty<Color> assetColor = asset.color();
if (assetColor.getValueOrNull() == null) {
assetColor.setNullableValue(myMonochromeColor.getValueOrNull());
}
myMonochromeActiveAssetBindings.bindTwoWay(myMonochromeColor, assetColor);
myMonochromeActiveAssetBindings.bind(monochromeIsResizable, asset.isResizable());
if (asset instanceof ImageAsset) {
myMonochromeActiveAssetBindings.bind(myMonochromeAssetValidityState, ((ImageAsset)asset).getValidityState());
}
else {
myMonochromeAssetValidityState.set(Validator.Result.OK);
}
}
getIconGenerator().monochromeImageAsset().setNullableValue(asset);
onAssetModified.run();
});
}
else {
// If monochrome is not supported we add all the non-monochrome observable listeners
myListeners
.listenAll(myForegroundTrimmed, myForegroundResizePercent, myForegroundColor,
myBackgroundTrimmed, myBackgroundResizePercent, myBackgroundColor,
myGenerateLegacyIcon, myLegacyIconShape,
myGenerateRoundIcon, myGeneratePlayStoreIcon, myGenerateWebpIcons)
.with(onAssetModified);
}
// Property to check if the asset used for foreground layer is resizable.
// This is used to show or hide controls based on the type of the asset.
// For example: the resize slider control.
BoolValueProperty foregroundIsResizable = new BoolValueProperty();
// Listens for changes to the controls on the foreground panel. When the asset is changed,
// it updates the controller bindings to match the properties of the new asset.
myListeners.listenAndFire(myForegroundActiveAsset, () -> {
myForegroundActiveAssetBindings.releaseAll();
BaseAsset asset = myForegroundActiveAsset.get();
myForegroundActiveAssetBindings.bindTwoWay(myForegroundTrimmed, asset.trimmed());
myForegroundActiveAssetBindings.bindTwoWay(myForegroundResizePercent, asset.scalingPercent());
OptionalValueProperty<Color> assetColor = asset.color();
if (assetColor.getValueOrNull() == null) {
assetColor.setNullableValue(myForegroundColor.getValueOrNull());
}
myForegroundActiveAssetBindings.bindTwoWay(myForegroundColor, assetColor);
myForegroundActiveAssetBindings.bind(foregroundIsResizable, asset.isResizable());
if (asset instanceof ImageAsset) {
myForegroundActiveAssetBindings.bind(myForegroundAssetValidityState, ((ImageAsset)asset).getValidityState());
}
else {
myForegroundAssetValidityState.set(Validator.Result.OK);
}
getIconGenerator().sourceAsset().setValue(asset);
onAssetModified.run();
});
BoolValueProperty backgroundIsResizable = new BoolValueProperty();
// When switching between Image/Color for background, bind corresponding properties and regenerate asset (to be sure).
Runnable onBackgroundAssetModified = () -> {
myBackgroundActiveAssetBindings.releaseAll();
ImageAsset asset = myBackgroundImageAsset.getValueOrNull();
if (asset != null) {
myBackgroundActiveAssetBindings.bindTwoWay(myBackgroundTrimmed, asset.trimmed());
myBackgroundActiveAssetBindings.bindTwoWay(myBackgroundResizePercent, asset.scalingPercent());
myBackgroundActiveAssetBindings.bind(backgroundIsResizable, asset.isResizable());
myBackgroundActiveAssetBindings.bind(myBackgroundAssetValidityState, asset.getValidityState());
}
else {
backgroundIsResizable.set(false);
myBackgroundAssetValidityState.set(Validator.Result.OK);
}
getIconGenerator().backgroundImageAsset().setNullableValue(asset);
onAssetModified.run();
};
myListeners.listenAndFire(myBackgroundImageAsset, onBackgroundAssetModified::run);
/*
* Hook up a bunch of UI <- boolean expressions, so that when certain conditions are met,
* various components show/hide. This also requires refreshing the panel explicitly, as
* otherwise Swing doesn't realize it should trigger a re-layout.
*/
ImmutableMap.Builder<BoolProperty, ObservableValue<Boolean>> layoutPropertiesBuilder = ImmutableMap.builder();
// Show and hide selected asset types for foreground layer
layoutPropertiesBuilder.put(new VisibleProperty(myForegroundImageAssetRowPanel), new SelectedProperty(myForegroundImageRadioButton));
layoutPropertiesBuilder.put(
new VisibleProperty(myForegroundClipartAssetRowPanel), new SelectedProperty(myForegroundClipartRadioButton));
layoutPropertiesBuilder.put(new VisibleProperty(myForegroundTextAssetRowPanel), new SelectedProperty(myForegroundTextRadioButton));
Expression<Boolean> isForegroundIsNotImage =
Expression.create(() -> myForegroundAssetType.get() != ForegroundAssetType.IMAGE, myForegroundAssetType);
layoutPropertiesBuilder.put(new VisibleProperty(myForegroundColorRowPanel), isForegroundIsNotImage);
if (HIDE_INAPPLICABLE_CONTROLS) {
layoutPropertiesBuilder.put(new VisibleProperty(myForegroundScalingTitleSeparator), foregroundIsResizable);
layoutPropertiesBuilder.put(new VisibleProperty(myForegroundImageOptionsPanel), foregroundIsResizable);
}
else {
layoutPropertiesBuilder.put(new EnabledProperty(myForegroundTrimYesRadioButton), foregroundIsResizable);
layoutPropertiesBuilder.put(new EnabledProperty(myForegroundTrimNoRadioButton), foregroundIsResizable);
layoutPropertiesBuilder.put(new EnabledProperty(myForegroundResizeSlider), foregroundIsResizable);
}
// Show and hide selected asset types for monochrome layer
if (myIsMonochromeSupported) {
layoutPropertiesBuilder.put(new VisibleProperty(myMonochromeImageAssetRowPanel), new SelectedProperty(myMonochromeImageRadioButton));
layoutPropertiesBuilder.put(
new VisibleProperty(myMonochromeClipartAssetRowPanel), new SelectedProperty(myMonochromeClipartRadioButton));
layoutPropertiesBuilder.put(new VisibleProperty(myMonochromeTextAssetRowPanel), new SelectedProperty(myMonochromeTextRadioButton));
Expression<Boolean> isMonochromeIsNotImage =
Expression.create(() -> myMonochromeAssetType.get() != MonochromeAssetType.IMAGE, myMonochromeAssetType);
layoutPropertiesBuilder.put(new VisibleProperty(myMonochromeColorRowPanel), isMonochromeIsNotImage);
if (HIDE_INAPPLICABLE_CONTROLS) {
layoutPropertiesBuilder.put(new VisibleProperty(myMonochromeScalingTitleSeparator), monochromeIsResizable);
layoutPropertiesBuilder.put(new VisibleProperty(myMonochromeImageOptionsPanel), monochromeIsResizable);
}
else {
layoutPropertiesBuilder.put(new EnabledProperty(myMonochromeTrimYesRadioButton), monochromeIsResizable);
layoutPropertiesBuilder.put(new EnabledProperty(myMonochromeTrimNoRadioButton), monochromeIsResizable);
layoutPropertiesBuilder.put(new EnabledProperty(myMonochromeResizeSlider), monochromeIsResizable);
}
}
// Show either the image or the color UI controls.
ObservableBool backgroundIsImage = new SelectedProperty(myBackgroundImageRadioButton);
ObservableBool backgroundIsColor = new SelectedProperty(myBackgroundColorRadioButton);
layoutPropertiesBuilder.put(new VisibleProperty(myBackgroundImageAssetRowPanel), backgroundIsImage);
layoutPropertiesBuilder.put(new VisibleProperty(myBackgroundColorRowPanel), backgroundIsColor);
if (HIDE_INAPPLICABLE_CONTROLS) {
layoutPropertiesBuilder.put(new VisibleProperty(myBackgroundScalingTitleSeparator), backgroundIsResizable);
layoutPropertiesBuilder.put(new VisibleProperty(myBackgroundImageOptionsPanel), backgroundIsResizable);
}
else {
layoutPropertiesBuilder.put(new EnabledProperty(myBackgroundTrimYesRadioButton), backgroundIsResizable);
layoutPropertiesBuilder.put(new EnabledProperty(myBackgroundTrimNoRadioButton), backgroundIsResizable);
layoutPropertiesBuilder.put(new EnabledProperty(myBackgroundResizeSlider), backgroundIsResizable);
}
layoutPropertiesBuilder.put(new EnabledProperty(myLegacyIconShapeComboBox), new SelectedProperty(myGenerateLegacyIconYesRadioButton));
ObservableBool isLauncherIcon = new BoolValueProperty(myIconType == AndroidIconType.LAUNCHER);
layoutPropertiesBuilder.put(new VisibleProperty(myLegacyIconShapeRowPanel), isLauncherIcon);
layoutPropertiesBuilder.put(new VisibleProperty(myGenerateRoundIconTitle), isLauncherIcon);
layoutPropertiesBuilder.put(new VisibleProperty(myGenerateRoundIconRowPanel), isLauncherIcon);
layoutPropertiesBuilder.put(new VisibleProperty(myGeneratePlayStoreIconTitle), isLauncherIcon);
layoutPropertiesBuilder.put(new VisibleProperty(myGeneratePlayStoreIconRowPanel), isLauncherIcon);
ImmutableMap<BoolProperty, ObservableValue<Boolean>> layoutProperties = layoutPropertiesBuilder.build();
for (Map.Entry<BoolProperty, ObservableValue<Boolean>> entry : layoutProperties.entrySet()) {
// Initialize everything off, as this makes sure the frame that uses this panel won't start
// REALLY LARGE by default.
entry.getKey().set(false);
myGeneralBindings.bind(entry.getKey(), entry.getValue());
}
myListeners.listenAll(layoutProperties.keySet()).with(() -> {
SwingUtilities.updateComponentTreeUI(myForegroundAllOptionsPanel);
if (myIsMonochromeSupported) {
SwingUtilities.updateComponentTreeUI(myMonochromeAllOptionsPanel);
}
SwingUtilities.updateComponentTreeUI(myBackgroundAllOptionsPanel);
SwingUtilities.updateComponentTreeUI(myOtherIconsAllOptionsPanel);
});
}