edu.caltech.ipac.firefly.ui.PopoutControlsUI.java Source code

Java tutorial

Introduction

Here is the source code for edu.caltech.ipac.firefly.ui.PopoutControlsUI.java

Source

/*
 * License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt
 */
package edu.caltech.ipac.firefly.ui;
/**
 * User: roby
 * Date: 9/14/11
 * Time: 10:57 AM
 */

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.DeckLayoutPanel;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.RequiresResize;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import edu.caltech.ipac.firefly.resbundle.images.IconCreator;
import edu.caltech.ipac.firefly.resbundle.images.VisIconCreator;
import edu.caltech.ipac.firefly.ui.input.CheckBoxGroupInputField;
import edu.caltech.ipac.firefly.ui.input.SimpleInputField;
import edu.caltech.ipac.firefly.util.Dimension;
import edu.caltech.ipac.firefly.util.WebClassProperties;
import edu.caltech.ipac.firefly.util.event.Name;
import edu.caltech.ipac.firefly.util.event.WebEvent;
import edu.caltech.ipac.firefly.util.event.WebEventListener;
import edu.caltech.ipac.firefly.visualize.AllPlots;
import edu.caltech.ipac.firefly.visualize.MiniPlotWidget;
import edu.caltech.ipac.util.dd.EnumFieldDef;

import java.util.ArrayList;
import java.util.List;

/**
* @author Trey Roby
*/
public class PopoutControlsUI {

    private static final int SINGLE_RESIZE_DELAY = 500;
    private static final int GRID_RESIZE_DELAY = 500;
    private static final IconCreator _ic = IconCreator.Creator.getInstance();
    private static final VisIconCreator _vic = VisIconCreator.Creator.getInstance();
    //    private static final TableImages _tableIM = TableImages.Creator.getInstance();

    private static final WebClassProperties _prop = new WebClassProperties(PopoutControlsUI.class);

    private static final String DEFAULT_TILE_TITLE = "Tiled View";
    private static String _tiledTitle = DEFAULT_TILE_TITLE;
    private VerticalPanel _oneImageNavigationPanel = null;
    private HorizontalPanel _controlPanel = null;
    private HorizontalPanel _topBar = null;
    private VerticalPanel _headerBarControls = new VerticalPanel();
    private HTML _goRight = new HTML();
    private HTML _goLeft = new HTML();
    private Image _goRightArrow = new Image(_vic.getSideRightArrow());
    private Image _goLeftArrow = new Image(_vic.getSideLeftArrow());

    private Grid _currentDisplayDots = new Grid(1, 1);
    private MyDeckLayoutPanel _expandDeck = new MyDeckLayoutPanel();
    private MyGridLayoutPanel _expandGrid = new MyGridLayoutPanel();
    private final HTML _expandTitleLbl = new HTML();
    private List<PopoutWidget> _expandedList;
    private List<PopoutWidget> _originalExpandedList;
    private final PopoutWidget _popoutWidget;
    private final PopoutWidget.Behavior _behavior;
    private String _expandedTitle = "";
    private boolean _resizeZoomEnabled = true;
    private boolean _fillStyleChangeEnabled = true;
    private final CheckBox blinkOp = GwtUtil.makeCheckBox("Auto Play", "blink the images 1 per second", false,
            true);
    private BlinkTimer blinkTimer = null;
    private CheckBox wcsSyncTargetOp;
    private CheckBox wcsSyncUserPos;

    public PopoutControlsUI(PopoutWidget popoutWidget, PopoutWidget.Behavior behavior,
            List<PopoutWidget> expandedList, List<PopoutWidget> originalExpandedList) {
        _popoutWidget = popoutWidget;
        _expandedList = expandedList;
        _behavior = behavior;
        _expandDeck.setStyleName("expand-deck");
        _originalExpandedList = originalExpandedList;
        popoutWidget.getExpandRoot().clear();
        initExpandControls();
    }

    public static void setTitledTitle(String title) {
        _tiledTitle = title;
    }

    public void freeResources() {
        doBlink(false);
        _oneImageNavigationPanel.clear();
        _controlPanel.clear();
        _headerBarControls.clear();
        _expandDeck.clear();
        _expandGrid.clear();
        if (_topBar != null)
            _topBar = new HorizontalPanel();
    }

    void setResizeZoomEnabled(boolean enable) {
        _resizeZoomEnabled = enable;
    }

    void updateList(List<PopoutWidget> expandedList, List<PopoutWidget> originalExpandedList) {
        _expandedList = expandedList;
        _originalExpandedList = originalExpandedList;
    }

    private void initExpandControls() {
        _oneImageNavigationPanel = new VerticalPanel();
        _controlPanel = new HorizontalPanel();

        _expandDeck.setAnimationDuration(0);
        Image oneTile = new Image(_ic.getOneTile());
        oneTile.setPixelSize(24, 24);
        Image gridIcon = new Image(_ic.getGrid());
        gridIcon.setPixelSize(24, 24);
        Image list = new Image(_ic.getList());
        list.setPixelSize(24, 24);

        createOneImageNavigationPanel();

        final GwtUtil.ImageButton one = GwtUtil.makeImageButton(oneTile, "Show single image at full size");
        final GwtUtil.ImageButton grid = GwtUtil.makeImageButton(gridIcon, "Show all as tiles");
        final GwtUtil.ImageButton choiceList = GwtUtil.makeImageButton(list, "Choose which plots to show");

        one.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                switchToOne();
            }
        });

        grid.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                switchToGrid();
            }
        });

        choiceList.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                showPlotChoiceDialog();
            }
        });

        GwtUtil.setStyle(one, "marginLeft", "11px");
        GwtUtil.setStyle(grid, "marginLeft", "11px");
        GwtUtil.setStyle(choiceList, "marginLeft", "11px");

        GwtUtil.setStyles(_expandTitleLbl, "fontSize", "10pt", "padding", "0px 0 0 5px", "lineHeight", "1.2em",
                "whiteSpace", "normal");

        HorizontalPanel totalControls = new HorizontalPanel();
        totalControls.add(_controlPanel);

        _headerBarControls.add(totalControls);

        if (_popoutWidget.getPopoutContainer().getHeaderBar() == null) {
            _topBar = new HorizontalPanel();
            _topBar.addStyleName("topBar");
            _topBar.add(_headerBarControls);
            _popoutWidget.getExpandRoot().addNorth(_topBar, PopoutWidget.CONTROLS_HEIGHT_LARGE);
            //            if (!AllPlots.getInstance().isMenuBarPopup()) {
            //                _popoutWidget.getExpandRoot().addSouth(AllPlots.getInstance().getMenuBarInlineStatusLine(), 20);
            //            }
        }

        GwtUtil.setStyle(_controlPanel, "paddingTop", "2px");

        wcsSyncTargetOp = GwtUtil.makeCheckBox("WCS Search Target Match",
                "Rotate and zoom all the plots so that their World Coordinates Systems match up",
                AllPlots.getInstance().isWCSMatch(), true);

        wcsSyncUserPos = GwtUtil.makeCheckBox("WCS Match",
                "Rotate and zoom all the plots so that their World Coordinates Systems match up",
                AllPlots.getInstance().isWCSMatch(), true);

        wcsSyncTargetOp.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
            public void onValueChange(ValueChangeEvent<Boolean> event) {
                disableBlink();
                if (wcsSyncTargetOp.getValue()) {
                    AllPlots.getInstance().enableWCSSync(AllPlots.WcsMatchMode.NorthAndCenter);
                } else {
                    AllPlots.getInstance().disableWCSMatch();
                }
                wcsSyncUserPos.setValue(false);
            }
        });

        wcsSyncUserPos.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
            public void onValueChange(ValueChangeEvent<Boolean> event) {
                disableBlink();
                if (wcsSyncUserPos.getValue()) {
                    AllPlots.getInstance().enableWCSSync(AllPlots.WcsMatchMode.ByUserPositionAndZoom);
                } else {
                    AllPlots.getInstance().disableWCSMatch();
                }
                wcsSyncTargetOp.setValue(false);
            }
        });

        AllPlots.getInstance().addListener(Name.WCS_SYNC_CHANGE, new WebEventListener<Boolean>() {
            public void eventNotify(WebEvent<Boolean> ev) {
                disableBlink();
                if (!AllPlots.getInstance().isWCSMatch()) {
                    wcsSyncTargetOp.setValue(false);
                    wcsSyncUserPos.setValue(false);
                }
            }
        });

        VerticalPanel opPan = new VerticalPanel();
        opPan.add(wcsSyncTargetOp);
        opPan.add(wcsSyncUserPos);
        opPan.add(blinkOp);
        GwtUtil.setStyle(opPan, "padding", "1px 0 0 11px");

        blinkOp.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
            public void onValueChange(ValueChangeEvent<Boolean> event) {
                doBlink(blinkOp.getValue());
            }
        });

        //        _controlPanel.setSpacing(7);
        PopoutContainer container = _popoutWidget.getPopoutContainer();
        if (container.isViewControlShowing())
            _controlPanel.add(one);
        if (container.isViewControlShowing())
            _controlPanel.add(grid);
        if (container.isImageSelectionShowing())
            _controlPanel.add(choiceList);
        if (container.isViewControlShowing())
            _controlPanel.add(opPan);
        _controlPanel.add(_oneImageNavigationPanel);

        GwtUtil.setHidden(blinkOp, true);
        GwtUtil.setHidden(wcsSyncTargetOp, true);
        GwtUtil.setHidden(wcsSyncUserPos, true);

    }

    void switchToOne() {
        int currIdx = 0;
        PopoutWidget currPopout = _behavior.chooseCurrentInExpandMode();
        if (currPopout != null)
            currIdx = _expandedList.indexOf(currPopout);
        if (currIdx == -1)
            currIdx = 0;
        _popoutWidget.showOneView(currIdx);
    }

    void switchToGrid() {
        _popoutWidget.showGridView();
    }

    public void doBlink(boolean start) {
        if (blinkTimer != null)
            blinkTimer.cancel();
        if (start) {
            blinkTimer = new BlinkTimer();
            blinkTimer.run();
        } else {
            blinkTimer = null;
        }

    }

    private void createOneImageNavigationPanel() {
        GwtUtil.setHidden(_oneImageNavigationPanel, true);

        ClickHandler goLeftHandler = new ClickHandler() {
            public void onClick(ClickEvent event) {
                goLeftNow();
            }
        };

        ClickHandler goRightHandler = new ClickHandler() {
            public void onClick(ClickEvent event) {
                goRightNow(false);
            }
        };

        GwtUtil.makeIntoLinkButton(_goLeft, _goLeftArrow);
        GwtUtil.makeIntoLinkButton(_goRight, _goRightArrow);

        _goLeft.addClickHandler(goLeftHandler);
        _goLeftArrow.addClickHandler(goLeftHandler);

        _goRight.addClickHandler(goRightHandler);
        _goRightArrow.addClickHandler(goRightHandler);

        HorizontalPanel hp = new HorizontalPanel();

        HorizontalPanel hpLeft = new HorizontalPanel();
        HorizontalPanel hpRight = new HorizontalPanel();
        hpLeft.add(_goLeftArrow);
        hpLeft.add(_goLeft);
        hpRight.add(_goRight);
        hpRight.add(_goRightArrow);
        hp.add(hpLeft);
        hp.add(hpRight);

        GwtUtil.setStyles(_goLeftArrow, "marginLeft", "4px", "textDecoration", "none", "fontSize", "10pt");

        GwtUtil.setStyles(_goLeft, "textOverflow", "ellipsis", "overflow", "hidden", "fontSize", "10pt", "padding",
                "2px 0 0 4px");

        GwtUtil.setStyles(_goRight, "padding", "2px 4px 0 11px", "textOverflow", "ellipsis", "overflow", "hidden",
                "textAlign", "right", "fontSize", "10pt");

        GwtUtil.setStyles(_goRightArrow, "textDecoration", "none", "fontSize", "10pt");
        hpRight.addStyleName("step-right");
        hpLeft.addStyleName("step-left");

        GwtUtil.setStyle(_oneImageNavigationPanel, "paddingLeft", "10px");

        _goLeft.setWidth("100px");
        _goRight.setWidth("100px");

        _oneImageNavigationPanel.add(hp);
        _oneImageNavigationPanel.add(_currentDisplayDots);
        _currentDisplayDots.setCellPadding(2);
        _oneImageNavigationPanel.setSpacing(2);
        _oneImageNavigationPanel.setCellHorizontalAlignment(_currentDisplayDots,
                HasHorizontalAlignment.ALIGN_CENTER);
    }

    //    private PopoutWidget.FillType getPlotFillStyle () {
    //        String v= oneImageFillStyle.getValue();
    //        PopoutWidget.FillType retval;
    //
    //        if      (v.equals("level"))retval= PopoutWidget.FillType.OFF;
    //        else if (v.equals("fill")) retval= PopoutWidget.FillType.FILL;
    //        else if (v.equals("fit"))  retval= PopoutWidget.FillType.FIT;
    //        else                       retval= PopoutWidget.FillType.OFF;
    //
    //        fillStyle= retval;
    //        return retval;
    //    }

    void updateOneImageNavigationPanel() {
        int cnt = _expandDeck.getWidgetCount();
        if (_expandDeck.getWidgetCount() == 1) {
            GwtUtil.setHidden(_oneImageNavigationPanel, true);
            GwtUtil.setHidden(_goLeft, true);
            GwtUtil.setHidden(_goLeftArrow, true);
            GwtUtil.setHidden(blinkOp, true);
            updateExpandedTitle(_expandedList.get(0));

        } else if (_expandDeck.getWidgetCount() > 1) {
            GwtUtil.setHidden(_oneImageNavigationPanel, false);
            GwtUtil.setHidden(_goLeft, _expandDeck.getWidgetCount() < 3);
            GwtUtil.setHidden(_goLeftArrow, _expandDeck.getWidgetCount() < 3);
            GwtUtil.setHidden(blinkOp, false);
            int curr = _expandDeck.getVisibleWidgetIndex();
            updateWcsShowing(_expandedList.get(curr));

            PopoutWidget right = (curr != cnt - 1) ? _expandedList.get(curr + 1) : _expandedList.get(0);
            PopoutWidget left = (curr != 0) ? _expandedList.get(curr - 1) : _expandedList.get(cnt - 1);

            if (_expandDeck.getWidgetCount() > 2)
                _goLeft.setHTML(left.getExpandedTitle(true));
            _goRight.setHTML(right.getExpandedTitle(true) + " ");
            //            pos.setText("showing " + (curr + 1) + " of " + cnt);

            if (_currentDisplayDots.getColumnCount() != cnt) {
                _currentDisplayDots.resize(1, cnt);
            }
            for (int i = 0; (i < cnt); i++) {
                if (i == curr) {
                    _currentDisplayDots.setWidget(0, i, new Image(_ic.getGreenDot()));
                } else {
                    Image im = new Image(_ic.getBlueDot());
                    im.addClickHandler(new DotClick(i));
                    _currentDisplayDots.setWidget(0, i, im);
                }
            }

            updateExpandedTitle(_expandedList.get(curr));

        } else {
            GwtUtil.setHidden(_oneImageNavigationPanel, true);
            GwtUtil.setHidden(_goLeft, true);
            GwtUtil.setHidden(_goLeftArrow, true);
            GwtUtil.setHidden(blinkOp, true);

            updateWcsShowing(null);
        }
    }

    private void updateWcsShowing(PopoutWidget newW) {
        int mpwCnt = 0;
        for (PopoutWidget pw : _expandedList) {
            if (pw instanceof MiniPlotWidget) {
                mpwCnt++;
            }
        }
        boolean externalWidget = (newW != null && !(newW instanceof MiniPlotWidget));
        GwtUtil.setHidden(wcsSyncTargetOp, mpwCnt < 2 || externalWidget);
        GwtUtil.setHidden(wcsSyncUserPos, mpwCnt < 2 || externalWidget);
    }

    private void goRightNow(boolean usingBlink) {
        int len = _expandDeck.getWidgetCount();
        int curr = _expandDeck.getVisibleWidgetIndex();
        int next = curr < len - 1 ? curr + 1 : 0;
        PopoutWidget currW = _expandedList.get(curr);
        PopoutWidget nextW = _expandedList.get(next);
        oneImagePage(currW, nextW);
        if (!usingBlink)
            disableBlink();
    }

    private void disableBlink() {
        blinkOp.setValue(false);
        doBlink(false);
    }

    private void goLeftNow() {
        int len = _expandDeck.getWidgetCount();
        int curr = _expandDeck.getVisibleWidgetIndex();
        int next = curr > 0 ? curr - 1 : len - 1;
        PopoutWidget currW = _expandedList.get(curr);
        PopoutWidget nextW = _expandedList.get(next);
        oneImagePage(currW, nextW);
        blinkOp.setValue(false);
        disableBlink();
    }

    private void oneImagePage(PopoutWidget oldPW, PopoutWidget newPW) {
        Dimension d = _popoutWidget.getPopoutContainer().getAvailableSize();
        _behavior.onPrePageInExpandedMode(oldPW, newPW, d);
        _expandDeck.showWidget(_expandedList.indexOf(newPW));
        updateOneImageNavigationPanel();
        _behavior.onPostPageInExpandedMode(oldPW, newPW, d);
        updateWcsShowing(newPW);
    }

    public void updateExpandedTitle(PopoutWidget popout) {
        if (popout == null)
            return;
        if (popout.isExpandedGridView()) {
            _expandedTitle = _tiledTitle;
            _expandTitleLbl.setHTML(_expandedTitle);
            _popoutWidget.getPopoutContainer().setTitle(_expandTitleLbl);
        } else {
            _expandedTitle = popout.getExpandedTitle(true);
            _expandTitleLbl.setHTML(_expandedTitle + popout.getSecondaryTitle());
            _popoutWidget.getPopoutContainer().setTitle(_expandTitleLbl);
        }
    }

    public int getVisibleIdxInOneMode() {
        int retval = -1;
        if (PopoutWidget.getViewType() == PopoutWidget.ViewType.ONE || _expandedList.size() == 1) {
            retval = _expandDeck.getVisibleWidgetIndex();
        }
        return retval;

    }

    private void showPlotChoiceDialog() {
        PopoutWidget curr = null;
        if (PopoutWidget.getViewType() == PopoutWidget.ViewType.ONE || _expandedList.size() == 1) {
            int idx = _expandDeck.getVisibleWidgetIndex();
            if (idx > -1) {
                curr = _expandedList.get(idx);
            }
        }
        final PopoutWidget currPopout = curr;

        EnumFieldDef fd = new EnumFieldDef();
        List<EnumFieldDef.Item> inputs = new ArrayList<EnumFieldDef.Item>(_expandedList.size());
        fd.setOrientation(EnumFieldDef.Orientation.Vertical);
        int i = 0;
        String value = "";
        for (PopoutWidget p : _originalExpandedList) {
            EnumFieldDef.Item item = new EnumFieldDef.Item(i + "", p.getExpandedTitle(true));
            inputs.add(item);
            if (_expandedList.contains(p))
                value += i + ",";
            i++;
        }
        value = value.substring(0, value.length() - 1);
        fd.addItems(inputs);
        final SimpleInputField checkBoxes = new SimpleInputField(new CheckBoxGroupInputField(fd),
                new SimpleInputField.Config(), false);
        checkBoxes.setValue(value);
        PopupUtil.showInputDialog(_popoutWidget.getExpandRoot(), "choose which", checkBoxes, new ClickHandler() {
            public void onClick(ClickEvent event) {
                setupNewExpandList(currPopout, checkBoxes);
            }
        }, null);
    }

    //todo - use this a template
    void setupNewExpandList(PopoutWidget currPopout, SimpleInputField checkBoxes) {
        String selectedAry[] = checkBoxes.getValue().split(",");
        _expandedList.clear();
        for (String s : selectedAry) {
            _expandedList.add(_originalExpandedList.get(Integer.parseInt(s)));
        }
        redisplay(currPopout);
    }

    void redisplay(PopoutWidget currPopout) {
        if (PopoutWidget.getViewType() == PopoutWidget.ViewType.ONE || _expandedList.size() == 1) {
            int currIdx = _expandedList.indexOf(currPopout);
            _popoutWidget.showOneView(currIdx > -1 ? currIdx : 0);
        } else if (PopoutWidget.getViewType() == PopoutWidget.ViewType.GRID) {
            _popoutWidget.showGridView();
        }
    }

    void addHeaderBar() {
        Panel headerBar = _popoutWidget.getPopoutContainer().getHeaderBar();
        if (headerBar != null)
            headerBar.add(_headerBarControls);
    }

    void removeHeaderBar() {
        Panel headerBar = _popoutWidget.getPopoutContainer().getHeaderBar();
        if (headerBar != null)
            headerBar.remove(_headerBarControls);
        //        LayoutManager lm= Application.getInstance().getLayoutManager();
        //        if (!AllPlots.getInstance().isMenuBarPopup()) {
        //            Region helpReg= lm.getRegion(LayoutManager.VIS_MENU_HELP_REGION);
        //            helpReg.setDisplay(AllPlots.getInstance().getMenuBarInlineStatusLine());
        //        }
    }

    void reinit(PopoutWidget.ViewType viewType, DockLayoutPanel expandRoot) {
        expandRoot.clear();
        doBlink(false);
        _expandGrid.clear();
        _expandDeck.clear();
        if (_topBar != null)
            expandRoot.addNorth(_topBar, PopoutWidget.CONTROLS_HEIGHT_LARGE);
        //        if (!AllPlots.getInstance().isMenuBarPopup()) {
        //            expandRoot.addSouth(AllPlots.getInstance().getMenuBarInlineStatusLine(),25);
        //        }
        if (viewType == PopoutWidget.ViewType.GRID) {
            expandRoot.add(_expandGrid);
            _expandGrid.setPixelSize(expandRoot.getOffsetWidth(), expandRoot.getOffsetHeight());
            //            GwtUtil.setHidden(oneImageFillStyle, true);
        } else if (viewType == PopoutWidget.ViewType.ONE) {
            expandRoot.add(_expandDeck);
            //            GwtUtil.setHidden(oneImageFillStyle, false);
        }
        GwtUtil.setHidden(_controlPanel, _originalExpandedList.size() <= 1);

    }

    public DeckLayoutPanel getDeck() {
        return _expandDeck;
    }
    //    public MyGridLayoutPanel getGrid() { return _expandGrid; }

    public void resizeGrid(int rows, int cols) {
        _expandGrid.resize(rows, cols);
        _expandGrid.setCellPadding(1);
    }

    public void setGridWidget(int row, int col, Widget w) {
        _expandGrid.setWidget(row, col, w);
    }

    class MyDeckLayoutPanel extends DeckLayoutPanel {

        private OneResizeTimer _oneResizeTimer = new OneResizeTimer();

        @Override
        public void onResize() {
            Widget p = getParent();
            if (!GwtUtil.isOnDisplay(p))
                return;
            super.onResize(); //To change body of overridden methods use File | Settings | File Templates.
            int w = p.getOffsetWidth();
            int h = (p.getOffsetHeight());

            int hAdjust = 0;
            if (!AllPlots.getInstance().isMenuBarPopup()) {
                hAdjust = 20;
            }
            for (PopoutWidget popout : _expandedList) {
                popout.getMovablePanel().setPixelSize(w, h - hAdjust);
                popout.getMovablePanel().forceLayout();
            }
            _oneResizeTimer.cancel();
            _oneResizeTimer.setupCall(w, h, _resizeZoomEnabled);
            _oneResizeTimer.schedule(SINGLE_RESIZE_DELAY);
        }
    }

    public Dimension getGridDimension() {
        Widget p = _expandGrid.getParent();
        if (!GwtUtil.isOnDisplay(p))
            return null;
        return getGridDimension(_expandGrid.getRowCount(), _expandGrid.getColumnCount());
    }

    public Dimension getGridDimension(int rows, int cols) {
        final int margin = 4;
        final int panelMargin = 14;
        Widget p = _expandGrid.getParent();
        if (!GwtUtil.isOnDisplay(p))
            return null;
        int w = (p.getOffsetWidth() - panelMargin) / cols - margin;
        int h = (p.getOffsetHeight() - panelMargin) / rows - margin;
        return new Dimension(w, h);
    }

    class MyGridLayoutPanel extends Grid implements RequiresResize {

        private GridResizeTimer _gridResizeTimer = new GridResizeTimer();

        public void onResize() {
            Dimension dim = getGridDimension();
            if (dim == null)
                return;
            int w = dim.getWidth();
            int h = dim.getHeight();
            this.setPixelSize(w, h);
            for (PopoutWidget popout : _expandedList) {
                popout.getMovablePanel().setPixelSize(w, h);
                popout.getMovablePanel().forceLayout();
            }
            _gridResizeTimer.cancel();
            _gridResizeTimer.setupCall(w, h, _resizeZoomEnabled);
            _gridResizeTimer.schedule(GRID_RESIZE_DELAY);
        }
    }

    private class GridResizeTimer extends Timer {
        private int w = 0;
        private int h = 0;
        private boolean adjustZoom;

        public void setupCall(int w, int h, boolean adjustZoom) {
            this.w = w;
            this.h = h;
            this.adjustZoom = adjustZoom;
        }

        @Override
        public void run() {
            _behavior.onGridResize(_expandedList, new Dimension(w, h), adjustZoom);
        }
    }

    private class OneResizeTimer extends Timer {
        private int w = 0;
        private int h = 0;
        private boolean adjustZoom;

        public void setupCall(int w, int h, boolean adjustZoom) {
            this.w = w;
            this.h = h;
            this.adjustZoom = adjustZoom;
        }

        @Override
        public void run() {
            int curr = _expandDeck.getVisibleWidgetIndex();
            if (curr > -1) {
                PopoutWidget popout = _expandedList.get(curr);
                _behavior.onSingleResize(popout, new Dimension(w, h), adjustZoom);
            }
        }
    }

    private class BlinkTimer extends Timer {

        @Override
        public void run() {
            if (blinkOp.getValue()) {
                goRightNow(true);
                schedule(1200);
            }
        }
    }

    private class DotClick implements ClickHandler {
        private final int _idx;

        public DotClick(int idx) {
            _idx = idx;
        }

        public void onClick(ClickEvent event) {
            int curr = _expandDeck.getVisibleWidgetIndex();
            PopoutWidget currW = _expandedList.get(curr);
            PopoutWidget nextW = _expandedList.get(_idx);
            oneImagePage(currW, nextW);
            disableBlink();
        }
    }
}