/* * 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 java.util.HashMap; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.PushButton; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.ToggleButton; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; /** * A control panel for the slide show. * * <p>The control panel consists of up to * four buttons: back, gallery, play, next and an optional progress bar. * In addition to that the control panel can "swallow" a film strip which * will be placed in the middle between the gallery and the play button. * * @author eckhart * */ public class ControlPanel extends Composite implements ClickHandler, SlideshowListener, ResizeListener, AttachmentListener, SlideshowControl { /** Constants (bit values) for the control panel buttons */ // public static final int BEGIN = 1, BACK = 2, HOME = 4, PLAY = 8, NEXT = 16, END = 32; public static final int BACK = 1; /** Constants (bit values) for the control panel buttons */ // public static final int BEGIN = 1, BACK = 2, HOME = 4, PLAY = 8, NEXT = 16, END = 32; public static final int HOME = 2; /** Constants (bit values) for the control panel buttons */ // public static final int BEGIN = 1, BACK = 2, HOME = 4, PLAY = 8, NEXT = 16, END = 32; public static final int NEXT = 8; /** Constants (bit values) for the control panel buttons */ // public static final int BEGIN = 1, BACK = 2, HOME = 4, PLAY = 8, NEXT = 16, END = 32; public static final int PLAY = 4; /** an array of the possible pixel sizes of the buttons */ protected static final int[] ICON_SIZES = { 16, 24, 32, 48, 64 }; /** * the base names (without size appendices, e.g. "_32" for the 32 pixel size * version of a button) of image files of the control buttons */ // protected static final String[] BASE_NAMES = { "begin", "begin_down", // "back", "back_down", "gallery", "gallery_down", "play", "pause", // "next", "next_down", "end", "end_down" }; protected static final String[] BASE_NAMES = { "back", "back_down", "gallery", "gallery_down", "play", "pause", "next", "next_down" }; /** a map that contains for each possible pixel size of the buttons another * map which maps the base name of the button to its image object */ static HashMap<Integer, HashMap<String, Image>> iconSets; static { iconSets = new HashMap<Integer, HashMap<String, Image>>(); for (int i: ICON_SIZES) iconSets.put(i, ControlPanel.loadImageSet(i)); } /** * Loads a set of icons for the control buttons corresponding to the given * <code>size</code>. The icons must be stored in the "icons" sub-directory * and be named appropriately, e.g. "next_down_24.png" is the icon with an * edge size of 24 pixels for the "next" button when it is pressed. * @param size the size of the icons. * @return a map where the respective images are indexed by their * name (without suffix or size indicator, e.g. a proper * index would be "next_down" but not "next_down_24.png" */ protected static HashMap<String, Image> loadImageSet(int size) { HashMap<String, Image> is = new HashMap<String, Image>(); String suffix = "_" + String.valueOf(size) + ".png"; for (String bn: BASE_NAMES) { String name = "icons/" + bn + suffix; Image img = new Image(name); // img.addStyleName("icon"); is.put(bn, img); } return is; } private ClickHandler homeButtonHandler; private HandlerRegistration homeButtonRegistration; private HashMap<String, Image> icons; private Filmstrip filmstrip; private ProgressBar progress; private PushButton back, home, next; // begin and end are not needed any more private ToggleButton play; private SimplePanel wrapper; private Slideshow slideshow; private Tooltip backTooltip, homeTooltip, playPauseTooltip, nextTooltip; private int buttonSize; // private boolean hasProgressBar = true; private boolean autoResize = true; private int buttonsEnabled = NEXT|HOME|PLAY|BACK; private int buttonsShown = NEXT|HOME|PLAY|BACK; /** * The constructor of class <code>ControlPanel</code>. The control panel * is initialized with a slide show. By default it features a progress bar * and all buttons are visible and enabled. * * @param slideshow the slide show to which this control panel shall be * attached */ public ControlPanel(Slideshow slideshow) { this.slideshow = slideshow; this.slideshow.addSlideshowListener(this); this.slideshow.getImagePanel().addAttachmentListener(this); wrapper = new SimplePanel(); wrapper.setStyleName("controlPanel"); buttonSize = ICON_SIZES[0]; icons = iconSets.get(buttonSize); // beginTooltip = new Tooltip(I18N.i18n.begin()); // endTooltip = new Tooltip(I18N.i18n.end()); backTooltip = new Tooltip(I18N.i18n.back()); nextTooltip = new Tooltip(I18N.i18n.next()); homeTooltip = new Tooltip(I18N.i18n.home()); playPauseTooltip = new Tooltip(I18N.i18n.playPause()); composePanel(); initWidget(wrapper); } // /** // * Allows automatic adjustment of the size of the control panel if the size // * of the image panel changes. // */ // public void allowAutoResize() { // autoResize = true; // } // // /** // * Disallows automatic adjustment of the size of the control panel if the size // * of the image panel changes. // */ // public void disallowAutoResize() { // autoResize = false; // } /** * Returns the size of the control buttons as integer value. The size is * automatically adjusted by the <code>onResized</code> method. It is * guaranteed to have a value greater or equal than 8 and smaller or equal * than 128, but usually it is one of the values: 16,24,32,40,48,64. * @return the edge size of the control buttons in pixel. */ public int getCrtlBtnSize() { return buttonSize; } /** * Returns true if the control panel has swallowed (i.e. contains) a * film strip. * @return true, if control panel contains a film strip */ public boolean hasFilmStrip() { return filmstrip != null; } // /** // * Returns the "swallowed" film strip or <code>null</code> if the control // * panel does not contain a film strip. // * @return reference to the film strip of the panel or <code>null</code> // */ // public Filmstrip getFilmstrip() { // return filmstrip; // } // /** // * Hides the progress bar. // */ // public void hideProgressBar() { // if (hasProgressBar) { // hasProgressBar = false; // composePanel(); // } // } /* (non-Javadoc) * @see com.google.gwt.user.client.ui.ClickListener.onClick() */ /* (non-Javadoc) * @see de.eckhartarnold.client.SlideshowControl#onClick(com.google.gwt.event.dom.client.ClickEvent) */ @Override public void onClick(ClickEvent event) { Object sender = event.getSource(); if (sender == back) { slideshow.stop(); slideshow.back(); } else if (sender == next) { slideshow.stop(); slideshow.next(); // } else if (sender == begin) { // slideshow.stop(); // slideshow.show(0); // } else if (sender == end) { // slideshow.stop(); // slideshow.show(slideshow.size()-1); } else if (sender == play) { if (play.isDown()) { slideshow.next(); slideshow.start(); } else { slideshow.stop(); } } // else { // sender == gallery // } } /* (non-Javadoc) * @see de.eckhartarnold.client.SlideshowListener.onFade() */ /* (non-Javadoc) * @see de.eckhartarnold.client.SlideshowControl#onFade() */ @Override public void onFade() { progress.setValue(slideshow.getCurrentSlide()+1); if (filmstrip != null) filmstrip.focusImage(slideshow.getCurrentSlide()); } /* (non-Javadoc) * @see de.eckhartarnold.client.AttachmentListener#onLoad(com.google.gwt.user.client.ui.Widget) */ /* (non-Javadoc) * @see de.eckhartarnold.client.SlideshowControl#onLoad(com.google.gwt.user.client.ui.Widget) */ @Override public void onLoad(Widget sender) { // beginTooltip.setMaxAppearances(2); // endTooltip.setMaxAppearances(2); backTooltip.setMaxAppearances(2); nextTooltip.setMaxAppearances(2); homeTooltip.setMaxAppearances(4); playPauseTooltip.setMaxAppearances(3); } /* (non-Javadoc) * @see de.eckhartarnold.client.ResizeListener.onResized() */ /* (non-Javadoc) * @see de.eckhartarnold.client.SlideshowControl#onResized() */ @Override public void onResized() { if (autoResize) { // final int[][] resolutions = {{640,480}, {800, 600}, {1024,768}, // {1280, 1024}, {1680, 1050}}; final int[][] resolutions = {{320,240}, {640, 480}, {1024, 600}, {1440, 1050}, {1920, 1200}}; final int[] btnSizes = {16, 24, 32, 40, 48, 64, 64}; int w = slideshow.getImagePanel().getOffsetWidth(); int h = Toolbox.getOffsetHeight(slideshow.getImagePanel()); // GWT.log("ControlPanel.onResized: panel dimensions: "+String.valueOf(w)+"x"+String.valueOf(h)); int i; for (i = 0; i < resolutions.length; i++) { int res[] = resolutions[i]; if (w < res[0] || h < res[1]) break; } if (filmstrip != null) i++; // don't remove this line or switching from normal ctrl panel to filmstrip might get problems! // GWT.log("ControlPanel.onResized: ButtonSize: "+String.valueOf(btnSizes[i])); setCtrlBtnSizePx(btnSizes[i]); } if (filmstrip != null) filmstrip.onResized(); } /* (non-Javadoc) * @see de.eckhartarnold.client.SlideshowListener.onShow() */ /* (non-Javadoc) * @see de.eckhartarnold.client.SlideshowControl#onShow(int) */ @Override public void onShow(int slideNr) { progress.setValue(slideNr+1); if (filmstrip != null) { filmstrip.focusImage(slideNr); } } /* (non-Javadoc) * @see de.eckhartarnold.client.SlideshowListener.onStart() */ /* (non-Javadoc) * @see de.eckhartarnold.client.SlideshowControl#onStart() */ @Override public void onStart() { if (!play.isDown()) { play.setDown(true); } } /* (non-Javadoc) * @see de.eckhartarnold.client.SlideshowListener.onStop() */ /* (non-Javadoc) * @see de.eckhartarnold.client.SlideshowControl#onStop() */ @Override public void onStop() { if (play.isDown()) { play.setDown(false); } } /* (non-Javadoc) * @see de.eckhartarnold.client.AttachmentListener#onUnload(com.google.gwt.user.client.ui.Widget) */ /* (non-Javadoc) * @see de.eckhartarnold.client.SlideshowControl#onUnload(com.google.gwt.user.client.ui.Widget) */ @Override public void onUnload(Widget sender) { // beginTooltip.hide(); // endTooltip.hide(); backTooltip.hide(); nextTooltip.hide(); homeTooltip.hide(); playPauseTooltip.hide(); } /* (non-Javadoc) * @see de.eckhartarnold.client.ResizeListener.prepareResized() */ /* (non-Javadoc) * @see de.eckhartarnold.client.SlideshowControl#prepareResized() */ @Override public void prepareResized() { if (filmstrip != null) filmstrip.prepareResized(); } // /** // * Determines which buttons are enabled on the panel. If the play button is // * disabled, the slide show will be stopped in case it was running. // * // * @param buttonFlags the bit set of the buttons that are to be enabled // */ // public void setButtonEnabled(int buttonFlags) { // buttonsEnabled = buttonFlags; // if ((buttonsEnabled & PLAY) == 0) slideshow.stop(); // enableOrDisableButtons(); // } // /** // * Determines which buttons are shown on the panel. If the play button is // * hidden the slide show will be stopped in case it was running. // * // * @param buttonFlags the bit set of the buttons that are to be shown // */ // public void setButtonShow(int buttonFlags) { // boolean redoPanel; // if (buttonsShown != buttonFlags) { // redoPanel = true; // } else { // redoPanel = false; // } // buttonsShown = buttonFlags; // if ((buttonsShown & PLAY) == 0) slideshow.stop(); // if (redoPanel) composePanel(); // } /** * Sets the size of the control buttons. If the new size is widely different * form the old one, this involves picking a fresh set of icons for the * control buttons. * * @param size the edge size of each control button in pixel. */ public void setCtrlBtnSizePx(int size) { assert size >= 16 && size <= 128; if (buttonSize == size) return; buttonSize = size; HashMap<String, Image> match = iconSets.get(ICON_SIZES[ICON_SIZES.length-1]); for (int i: ICON_SIZES) { if (size <= i) { match = iconSets.get(i); break; } } // need to set sizes for images that are still loading // using im.getHeight() to query sizes is a really bad idea before image // has been fully loaded! for (Image im: match.values()) im.setPixelSize(size/2, size); // size/2 only works with the grey icons set! for the colored icon set use size * 3 / 4 if (match != icons || filmstrip != null) { icons = match; // wrapper.remove(panel); composePanel(); } } /* (non-Javadoc) * @see de.eckhartarnold.client.SlideshowControl#setHomeButtonListener(com.google.gwt.event.dom.client.ClickHandler) */ @Override public void setHomeButtonListener(ClickHandler handler) { if (home != null) { if (homeButtonRegistration != null) { homeButtonRegistration.removeHandler(); } homeButtonRegistration = home.addClickHandler(handler); } homeButtonHandler = handler; } // /** // * Shows the progress bar. // */ // public void showProgressBar() { // if (!hasProgressBar) { // hasProgressBar = true; // composePanel(); // } // } /** * Swallows a {@link Filmstrip} widget. The film strip will then become part * of the control panel. The control panel will automatically be resized so * that it covers the full width of the browser window (or the parent widget). * @param filmstrip the film strip widget * @param selectableImages true, if the images of the film strip shall be * made selectable so that by clicking on one them * the slide show jumps to that image */ public void swallowFilmstrip(Filmstrip filmstrip, boolean selectableImages) { if (filmstrip != null && selectableImages) { filmstrip.setPickImageCallback(new Filmstrip.IPickImage() { public void onPickImage(int imageNr) { slideshow.stop(); slideshow.show(imageNr); } }); } if (this.filmstrip != filmstrip) { this.filmstrip = filmstrip; composePanel(); } } /** * (Re-)creates the button panel using the images stored in the * <code>icons</code> map as symbols on the buttons. */ protected void composePanel() { VerticalPanel vpanel = new VerticalPanel(); HorizontalPanel buttonPanel = new HorizontalPanel(); buttonPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); // progress bar progress = new ProgressBar(slideshow.size()); int btnSize; if (filmstrip != null) btnSize = buttonSize / 2; else btnSize = buttonSize; if (btnSize >= 24) progress.setLabelingType(ProgressBar.VALUE_LABEL); else progress.setLabelingType(ProgressBar.NO_LABEL); if (btnSize <= 32) progress.getFrame().addStyleDependentName("thin"); if(btnSize > 48) progress.getBar().addStyleDependentName("16px"); else if (btnSize > 32) progress.getBar().addStyleDependentName("12px"); else if (btnSize >= 28) progress.getBar().addStyleDependentName("10px"); else if (btnSize >= 24) progress.getBar().addStyleDependentName("9px"); else if (btnSize >= 20) progress.getBar().addStyleDependentName("4px"); else progress.getBar().addStyleDependentName("3px"); int value = slideshow.getCurrentSlide(); if (value >= 0) progress.setValue(value+1); // button panel // begin = new PushButton(icons.get("begin"), icons.get("begin_down"), this); // Tooltip.addToWidget(beginTooltip, begin); back = new PushButton(icons.get("back"), icons.get("back_down"), this); Tooltip.addToWidget(backTooltip, back); if (homeButtonHandler != null) { home = new PushButton(icons.get("gallery"), icons.get("gallery_down"), homeButtonHandler); } else { home = new PushButton(icons.get("gallery"), icons.get("gallery_down")); } Tooltip.addToWidget(homeTooltip, home); play = new ToggleButton(icons.get("play"), icons.get("pause"), this); Tooltip.addToWidget(playPauseTooltip, play); if (slideshow.isRunning()) play.setDown(true); next = new PushButton(icons.get("next"), icons.get("next_down"), this); Tooltip.addToWidget(nextTooltip, next); // end = new PushButton(icons.get("end"), icons.get("end_down"), this); // Tooltip.addToWidget(endTooltip, end); // if ((buttonsShown & BEGIN) != 0) buttonPanel.add(begin); if ((buttonsShown & BACK) != 0) buttonPanel.add(back); if ((buttonsShown & HOME) != 0) buttonPanel.add(home); if (filmstrip != null) { filmstrip.setHeight(buttonSize*2+"px"); vpanel.add(filmstrip); vpanel.add(progress); vpanel.setWidth("100%"); buttonPanel.add(vpanel); buttonPanel.setCellWidth(vpanel, "100%"); buttonPanel.addStyleName("controlFilmstripBackground"); addButtonStyles("controlFilmstripButton"); } else { buttonPanel.addStyleName("controlPanelBackground"); addButtonStyles("controlPanelButton"); } if ((buttonsShown & PLAY) != 0) buttonPanel.add(play); if ((buttonsShown & NEXT) != 0) buttonPanel.add(next); // if ((buttonsShown & END) != 0) buttonPanel.add(end); enableOrDisableButtons(); if (filmstrip != null) { wrapper.setWidget(buttonPanel); } else { vpanel.add(buttonPanel); vpanel.add(progress); wrapper.setWidget(vpanel); } } /** * Transfers the state of the <code>buttonsEnabled</code> flags which * can be set with method <code>setButtonEnabled</code> to the button * widgets. */ protected void enableOrDisableButtons() { // begin.setEnabled((buttonsEnabled & BEGIN) != 0); back.setEnabled((buttonsEnabled & BACK) != 0); home.setEnabled((buttonsEnabled & HOME) != 0); play.setEnabled((buttonsEnabled & PLAY) != 0); next.setEnabled((buttonsEnabled & NEXT) != 0); // end.setEnabled((buttonsEnabled & END) != 0); } /** * Sets the stylenames for all buttons and the panel with the * addStyleName method. * @param buttonStyle css style for the buttons */ private void addButtonStyles(String buttonStyle) { // begin.addStyleName(buttonStyle); back.addStyleName(buttonStyle); home.addStyleName(buttonStyle); play.addStyleName(buttonStyle); next.addStyleName(buttonStyle); // end.addStyleName(buttonStyle); } }