// -*- 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
package com.google.appinventor.client.editor.simple.palette;
import com.google.appinventor.client.ComponentsTranslation;
import com.google.appinventor.client.editor.simple.components.MockComponent;
import com.google.appinventor.client.editor.simple.components.MockComponentsUtil;
import com.google.appinventor.client.widgets.dnd.DragSourcePanel;
import com.google.appinventor.client.widgets.dnd.DragSourceSupport;
import com.google.appinventor.client.widgets.dnd.DropTarget;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
/**
* This class represents a component on the component palette panel.
*
*/
public class SimplePaletteItem extends DragSourcePanel {
// Queried to determine the set of UI elements that accept drops of palette items
private DropTargetProvider dropTargetProvider;
// Component descriptor (needed for mock component instantiation)
private SimpleComponentDescriptor scd;
// Cached prototype of the component that this palette item creates.
// Properties of the prototype may be queried by accessors.
private MockComponent componentPrototype;
//It is here to keep the selected panel item
private static Widget selectedPaletteItemWidget;
/**
* Creates a new palette item.
*
* @param scd component descriptor for palette item
* @param dropTargetProvider provider of targets that palette items can be dropped on
*/
public SimplePaletteItem(SimpleComponentDescriptor scd, DropTargetProvider dropTargetProvider) {
this.dropTargetProvider = dropTargetProvider;
this.scd = scd;
componentPrototype = null;
// Initialize palette item UI
HorizontalPanel panel = new HorizontalPanel();
panel.setStylePrimaryName("ode-SimplePaletteItem");
Image image = scd.getImage();
image.setStylePrimaryName("ode-SimplePaletteItem-icon");
panel.add(image);
panel.setCellHorizontalAlignment(image, HorizontalPanel.ALIGN_LEFT);
panel.setCellWidth(image, "30px");
Label label = new Label(ComponentsTranslation.getComponentName(scd.getName()));
label.setHorizontalAlignment(Label.ALIGN_LEFT);
label.addStyleName("ode-SimplePaletteItem-caption");
panel.add(label);
HorizontalPanel optPanel = new HorizontalPanel();
ComponentHelpWidget helpImage = new ComponentHelpWidget(scd);
helpImage.addStyleName("ode-SimplePalleteItem-button");
optPanel.add(helpImage);
optPanel.setCellHorizontalAlignment(helpImage, HorizontalPanel.ALIGN_LEFT);
if (scd.getExternal()) {
ComponentRemoveWidget deleteImage = new ComponentRemoveWidget(scd);
deleteImage.addStyleName("ode-SimplePalleteItem-button");
optPanel.add(deleteImage);
optPanel.setCellHorizontalAlignment(deleteImage, HorizontalPanel.ALIGN_RIGHT);
}
panel.add(optPanel);
panel.setCellHorizontalAlignment(optPanel, HorizontalPanel.ALIGN_RIGHT);
panel.setWidth("100%");
add(panel);
setWidth("100%");
addHandlers();
}
/**
* Selects (sets the background to green of) a palette item when it is clicked.
*
* @param paletteItemWidget the Widget of the panel item to be selected
*/
private static void select(Widget paletteItemWidget) {
if (selectedPaletteItemWidget != null) {
selectedPaletteItemWidget.getElement().getStyle().setProperty("backgroundColor", "white");
}
selectedPaletteItemWidget = paletteItemWidget;
selectedPaletteItemWidget.getElement().getStyle().setProperty("backgroundColor", "#d2e0a6");
}
private void addHandlers() {
addMouseDownHandler(new MouseDownHandler() {
@Override
public void onMouseDown(MouseDownEvent arg0) {
select(getWidget());
}
});
}
/**
* Returns a new mock component for the palette item.
* <p>
* The caller is assumed to take ownership of the returned component.
*
* @return mock component
*/
public MockComponent createMockComponent() {
cacheInternalComponentPrototype();
MockComponent returnedComponentPrototype = componentPrototype;
componentPrototype = null;
return returnedComponentPrototype;
}
/**
* Returns whether this palette item creates components with a visual representation.
*/
public boolean isVisibleComponent() {
cacheInternalComponentPrototype();
return componentPrototype.isVisibleComponent();
}
private void cacheInternalComponentPrototype() {
if (componentPrototype == null) {
componentPrototype = scd.createMockComponentFromPalette();
}
}
// DragSource implementation
@Override
public void onDragStart() {
// no action
}
@Override
public Widget createDragWidget(int x, int y) {
MockComponent component = createMockComponent();
// Some components override getPreferredWidth/Height because getOffsetWidth/Height (which is
// what MockComponentsUtil.getPreferredSizeOfDetachedWidget uses) returns very inaccurate
// values. These components can give us the width/height even when the component is not
// attached.
int width = component.getPreferredWidth();
int height = component.getPreferredHeight();
if (width <= 0 && height <= 0) {
// Other components don't override getPreferredWidth/Height, which means that we'll get 0 (or
// less) because the component is not attached. So, we use getPreferredSizeOfDetachedWidget.
int[] size = MockComponentsUtil.getPreferredSizeOfDetachedWidget(component);
width = size[0];
height = size[1];
}
component.setPixelSize(width, height);
DragSourceSupport.configureDragWidgetToAppearWithCursorAt(component, width / 2, height / 2);
return component;
}
@Override
public Widget getDragWidget() {
return dragSourceSupport.getDragWidget();
}
@Override
public DropTarget[] getDropTargets() {
return dropTargetProvider.getDropTargets();
}
@Override
public void onDragEnd() {
// no action
}
// Utility methods
public String getName() {
return scd.getName();
}
}