// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
// TODO(user): reconsider visibilities of the abstract base classes in this package
package com.google.appinventor.client.editor.simple.components;
import com.google.appinventor.client.editor.simple.SimpleEditor;
import com.google.appinventor.client.output.OdeLog;
import com.google.common.primitives.Ints;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.dom.client.ErrorEvent;
import com.google.gwt.event.dom.client.ErrorHandler;
import com.google.gwt.event.dom.client.LoadEvent;
import com.google.gwt.event.dom.client.LoadHandler;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.SimplePanel;
/**
* Abstract superclass for MockImage and MockImageSprite.
*
* @author lizlooney@google.com (Liz Looney)
*/
abstract class MockImageBase extends MockVisibleComponent {
// Property names
private static final String PROPERTY_NAME_PICTURE = "Picture";
private static final String PROPERTY_SCALE_PICTURE_TO_FIT = "ScalePictureToFit";
private static final String PROPERTY_SCALING = "Scaling";
// Widget for showing the image.
private final Image image;
private String picturePropValue;
private String scalingMode = "0"; // corresponds to Scale proportionally
MockImageBase(SimpleEditor editor, String type, ImageResource icon) {
super(editor, type, icon);
image = new Image();
image.addErrorHandler(new ErrorHandler() {
@Override
public void onError(ErrorEvent event) {
if (picturePropValue != null && !picturePropValue.isEmpty()) {
OdeLog.elog("Error occurred while loading image " + picturePropValue);
}
refreshForm(true);
}
});
image.addLoadHandler(new LoadHandler() {
@Override
public void onLoad(LoadEvent event) {
refreshForm(true);
resizeImage(); // resize after the new image occupies the form
}
});
SimplePanel simplePanel = new SimplePanel();
simplePanel.setStylePrimaryName("ode-SimpleMockComponent");
simplePanel.addStyleName("imageComponentCenterPanel");
simplePanel.setWidget(image);
initComponent(simplePanel);
}
/*
* Sets the image's url to a new value.
*/
private void setPictureProperty(String text) {
picturePropValue = text;
String url = convertImagePropertyValueToUrl(text);
if (url == null) {
// text was not recognized as an asset. Just display the icon for this type of component.
image.setUrl(getIconImage().getUrl());
} else {
image.setUrl(url);
}
}
@Override
public int getPreferredWidth() {
// The superclass uses getOffsetWidth, which won't work for us.
// Hide away the current 100% size so we can get at the actual size, otherwise automatic size doesn't work
String[] style = MockComponentsUtil.clearSizeStyle(image);
int width = image.getWidth();
MockComponentsUtil.restoreSizeStyle(image, style);
return width;
}
@Override
public int getPreferredHeight() {
// The superclass uses getOffsetHeight, which won't work for us.
// Hide away the current 100% size so we can get at the actual size, otherwise automatic size doesn't work
String[] style = MockComponentsUtil.clearSizeStyle(image);
int height = image.getHeight();
MockComponentsUtil.restoreSizeStyle(image, style);
return height;
}
/**
* This resizes the picture according to
* 1. height and width value of the div tag enclosing the img tag
* 2. scaling mode. 0 - Scale proportionally, 1 - Scale to fit
* which correspond to the choices in ScalingChoicePropertyEditor
*
* This should be called whenever a property affecting the size is changed
*/
private void resizeImage() {
if (image.getUrl().equals(getIconImage().getUrl())) {
unclipImage();
return;
}
String width = getElement().getStyle().getWidth();
String height = getElement().getStyle().getHeight();
// the situation right after refreshing the page
if (width.isEmpty() || height.isEmpty()) {
return;
}
int frameWidth = Ints.tryParse(width.substring(0, width.indexOf("px")));
int frameHeight = Ints.tryParse(height.substring(0, height.indexOf("px")));
if (scalingMode.equals("0")) {
float ratio = Math.min(frameWidth / (float) getPreferredWidth(),
frameHeight / (float) getPreferredHeight());
int scaledWidth = Double.valueOf(getPreferredWidth() * ratio).intValue();
int scaledHeight = Double.valueOf(getPreferredHeight() * ratio).intValue();
image.setSize(scaledWidth + "px", scaledHeight + "px");
} else if (scalingMode.equals("1")) {
image.setSize("100%", "100%");
} else {
throw new IllegalStateException("Illegal scaling mode: " + scalingMode);
}
}
private void unclipImage() {
Style style = image.getElement().getStyle();
style.clearLeft();
style.clearTop();
style.clearWidth();
style.clearHeight();
}
// PropertyChangeListener implementation
@Override
public void onPropertyChange(String propertyName, String newValue) {
super.onPropertyChange(propertyName, newValue);
if (propertyName.equals(PROPERTY_NAME_PICTURE)) {
setPictureProperty(newValue); // setUrl() triggers onLoad
} else if (propertyName.equals(PROPERTY_NAME_WIDTH)) {
resizeImage();
refreshForm();
} else if (propertyName.equals(PROPERTY_NAME_HEIGHT)) {
resizeImage();
refreshForm();
} else if (propertyName.equals(PROPERTY_SCALING)) {
scalingMode = newValue;
resizeImage();
refreshForm();
} else if (propertyName.equals(PROPERTY_SCALE_PICTURE_TO_FIT)) {
boolean scaleIt = Boolean.parseBoolean(newValue);
if (scaleIt) {
scalingMode = "1";
} else {
scalingMode = "0";
}
resizeImage();
refreshForm();
}
}
}