/*
* Copyright 2008 Eckhart Arnold (eckhart_arnold@hotmail.com).
*
* 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 de.eckhartarnold.client;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.PopupPanel;
/**
* Encapsulates a caption in a transparent
* pop-up window over the image panel.
*
* <p>For better visibility, a
* shadow is added to the text (by placing under the overlay popup a second
* overlay popup with the same caption text but in black color and slightly
* moved to the lower right direction).
*
* Note: The CaptionOverlay should be added as WindowListener only after the
* caption itself has been added!
*/
public class CaptionOverlay implements SlideshowListener,
PopupPanel.PositionCallback, ResizeListener, AttachmentListener {
public final static String KEY_CAPTION_POSITION = "caption position";
public final static String TOP = "top",
BOTTOM = "bottom";
private static int MARGIN = 4;
private Caption caption;
private Widget baseWidget;
private boolean showAtTop = false;
private PopupPanel popup;
private CaptionOverlay shadow;
/**
* Creates a new overlay caption. An overlay caption is laid over some
* other widget, which is usually the <code>FlipImagePanel</code> which
* displays the slides.
*
* @param caption the caption which shall be overlaid
* @param baseWidget the base widget over which the caption shall be overlaid
* @param slideshow the slide show to which the captioned images belong
*/
public CaptionOverlay(Caption caption, Widget baseWidget,
Slideshow slideshow, String position) {
if (position == TOP) { // NO_SPACING leads to misplacement of shadows in some cases
caption.setSpacing(Caption.TOP_SPACING);
} else {
caption.setSpacing(Caption.BOTTOM_SPACING);
}
shadow = new CaptionOverlay(new Caption(caption), baseWidget, slideshow, position, true);
caption.addStyleDependentName("overlay");
init(caption, baseWidget, slideshow, position);
slideshow.addSlideshowListener(this);
}
/**
* Creates the shadow for an overlay caption. With this constructor the
* <code>CaptionOverlay</code> object functions as shadow. The difference
* to a normal <code>CaptionOverlay</code> object is that a shadow does
* not listen to the <code>Slideshow</code> events and that a shadow does
* not itself have a shadow (of course!).
*
* @param caption the caption which shall be overlaid
* @param baseWidget the base widget over which the caption shall be overlaid
* (usually an image panel)
* @param slideshow the slide show to which the captioned images belong
* @param dropShadow this parameter is only meant for differentiating the
* shadow constructor from the normal constructor. No
* matter what the value of this parameter is, an overlay
* object created with this constructor will always be a
* shadow!
*/
protected CaptionOverlay(Caption caption, Widget baseWidget,
Slideshow slideshow, String position, boolean dropShadow) {
shadow = null;
caption.addStyleDependentName("overlay-shadow");
init(caption, baseWidget, slideshow, position);
}
/**
* Returns the <code>showAtTop</code> property of the caption
* @return true if caption appears at the top, false otherwise
*/
public boolean getShowAtTop() {
return showAtTop;
}
/* (non-Javadoc)
* @see de.eckhartarnold.client.AttachmentListener#onLoad()
*/
public void onLoad(Widget sender) {
if (!caption.isEmpty()) {
popup.show();
}
}
/* (non-Javadoc)
* @see de.eckhartarnold.client.ResizeListener#onResized()
*/
public void onResized() {
caption.onResized(); // do this again, because the image panel size might have been changed meanwhile
if (shadow != null) {
shadow.onResized();
}
setPosition(popup.getOffsetWidth(), Toolbox.getOffsetHeight(popup));
}
/* (non-Javadoc)
* @see de.eckhartarnold.client.SlideshowListener#onFade()
*/
public void onFade() {
popup.hide();
if (shadow != null) shadow.onFade();
caption.onFade();
}
/* (non-Javadoc)
* @see de.eckhartarnold.client.SlideshowListener#onStart()
*/
public void onStart() { }
/* (non-Javadoc)
* @see de.eckhartarnold.client.SlideshowListener#onStop()
*/
public void onStop() { }
/* (non-Javadoc)
* @see de.eckhartarnold.client.SlideshowListener#onShow()
*/
public void onShow(int slideNr) {
popup.hide();
if (shadow != null) shadow.onShow(slideNr);
if (!caption.isEmpty())
popup.setPopupPositionAndShow(this);
}
/* (non-Javadoc)
* @see de.eckhartarnold.client.AttachmentListener#onUnload()
*/
public void onUnload(Widget sender) {
popup.hide();
}
/* (non-Javadoc)
* @see de.eckhartarnold.client.ResizeListener#prepareResized()
*/
public void prepareResized() {
if (shadow != null) shadow.caption.prepareResized();
}
/* (non-Javadoc)
* @see com.google.gwt.user.client.ui.PopupPanel.PositionCallback#setPosition()
*/
public void setPosition(int offsetWidth, int offsetHeight) {
int w = baseWidget.getOffsetWidth();
int h = Toolbox.getOffsetHeight(baseWidget);
int xpos = baseWidget.getAbsoluteLeft();
int ypos = baseWidget.getAbsoluteTop();
String align = caption.getElement().getStyle().getProperty("TextAlign");
if (align == "left") xpos += MARGIN;
else if (align == "right") xpos += w - offsetWidth - MARGIN;
else xpos += (w - offsetWidth) / 2;
if (showAtTop) ypos += MARGIN;
else ypos += h - offsetHeight - MARGIN;
int dX = 0, dY = 0;
if (shadow == null) {
if (caption.getFontSize() <= 14) {
dX = 1;
dY = 1;
} else {
dX = 2;
dY = 2;
}
}
popup.setPopupPosition(xpos+dX, ypos+dY);
}
/**
* Tells the <code>CaptionOverlay</code> whether the caption shall be shown
* at the top or at the bottom of the image.
*
* @param showAtTop true, if the caption is to be shown at the top
*/
public void setShowAtTop(boolean showAtTop) {
if (showAtTop != this.showAtTop) {
this.showAtTop = showAtTop;
if (showAtTop) {
caption.setSpacing(Caption.TOP_SPACING);
} else {
caption.setSpacing(Caption.BOTTOM_SPACING);
}
if (shadow != null) shadow.setShowAtTop(showAtTop);
if (popup.isShowing()) {
popup.hide();
popup.setPopupPositionAndShow(this);
}
}
}
/**
* An initialization function that contains code that would otherwise be
* common to several constructors.
*
* @param caption the caption
* @param baseWidget the base widget over which the caption shall be laid
* @param slideshow the slide show
*/
private void init(Caption caption, Widget baseWidget, Slideshow slideshow,
String position) {
this.caption = caption;
this.baseWidget = baseWidget;
popup = new PopupPanel();
popup.add(caption);
popup.addStyleName("captionPopup");
popup.setAnimationEnabled(false);
if (baseWidget instanceof SourcesAttachmentEvents) {
((SourcesAttachmentEvents) this.baseWidget).addAttachmentListener(this);
}
showAtTop = position == TOP;
}
}