Package com.google.gwt.widgetideas.client

Source Code of com.google.gwt.widgetideas.client.PinnedPanel$State

/*
* Copyright 2007 Google Inc.
*
* 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 com.google.gwt.widgetideas.client;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.ChangeListenerCollection;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.SourcesChangeEvents;
import com.google.gwt.user.client.ui.ToggleButton;
import com.google.gwt.user.client.ui.Widget;

/**
* {@link PinnedPanel} creates a panel that is, by default, pinned in place.
* When the pinned state it toggled, the contents of the panel will display only
* when the users mouse hovers over it, otherwise is will collapse to the left.
* A {@link ChangeEvent} is fired whenever the {@link PinnedPanel} changes it
* pinned state.
* <p>
* The default style name is gwt-PinnedPanel.
* <p>
* Planned enhancements: Allow panel to be collapsed in arbitrary direction.
*/


/**
* {@link PinnedPanel} creates a panel that is, by default, pinned in place.
* When the pinned state it toggled, the contents of the panel will display only
* when the users mouse hovers over it, otherwise is will collapse to the left.
* A {@link ChangeEvent} is fired whenever the {@link PinnedPanel} changes it
* pinned state.
* <p>
* The default style name is gwt-PinnedPanel.
* <p>
* Planned enhancements: Allow panel to be collapsed in arbitrary direction.
*/
public class PinnedPanel extends Composite implements SourcesChangeEvents {
  /**
   * Hides the {@link PinnedPanel}.
   */
  class HidingTimer extends SlidingTimer {
    protected void finish() {
      state.currentState = State.IS_HIDDEN;
    }

    protected boolean processSizeChange(float shouldBe) {
      currentOffshift =
          (int) (maxOffshift * ((float) 1.0 - shouldBe)) - MIN_SLIDE_STEP;
      currentOffshift = Math.max(currentOffshift, 0);
      impl.setPanelPos(currentOffshift);
      return currentOffshift > 0;
    }
  }

  /**
   * Shows the hovering {@link PinnedPanel}.
   */
  class ShowingTimer extends SlidingTimer {
    protected void finish() {
      state.currentState = State.IS_SHOWN;
    }

    protected boolean processSizeChange(float shouldBe) {
      currentOffshift = (int) (maxOffshift * shouldBe) + MIN_SLIDE_STEP;
      currentOffshift = Math.min(currentOffshift, maxOffshift);
      impl.setPanelPos(currentOffshift);
      return currentOffshift < maxOffshift;
    }
  }

  /**
   * Common code for {@link HidingTimer} and {@link ShowingTimer}.
   */
  abstract class SlidingTimer extends Timer {

    long started;

    boolean fireChangeListeners = false;

    public void run() {
      float hasTaken = System.currentTimeMillis() - started;
      float shouldBe = hasTaken / TIME_TO_SLIDE;

      if (processSizeChange(shouldBe)) {
        this.schedule(OVERLAY_SPEED);
      } else {
        if (fireChangeListeners) {
          changeListeners.fireChange(PinnedPanel.this);
          fireChangeListeners = false;
        }
        finish();
      }
    }

    protected abstract void finish();

    protected abstract boolean processSizeChange(float shouldBe);
  }

  /**
   * Delays showing of the {@link PinnedPanel}.
   */
  private class DelayShow extends Timer {

    public void activate() {
      state.currentState = State.WILL_SHOW;
      delayedShow.schedule(DELAY_MILLI);
    }

    public void run() {
      show();
    }
  }

  /**
   * Delays showing of the {@link PinnedPanel}.
   */
  private class DelayHide extends Timer {

    public void activate() {   
      state.currentState = State.WILL_HIDE;
      delayedHide.schedule(DELAY_MILLI);
    }

    public void run() {
      hide();
    }
  }
  /**
   * Pinned panel implementation. Factored out of {@link PinnedPanel} to allow
   * eventual use of differed bindings.
   */
  private static class PinnedPanelImpl {
    protected PinnedPanel pin;
    protected Element e;
    protected Element mover;

    public void setPinnedPanel(PinnedPanel pinnedPanel) {
      pin = pinnedPanel;
      e = pinnedPanel.getElement();
      mover = pinnedPanel.mover.getElement();
    }

    /**
     * Go into overlay mode.
     */
    protected void becomeOverlay() {
      int hoverBarWidth = pin.hoverContainer.getOffsetWidth();
      int aboutHalf = (hoverBarWidth / 2) + 1;
      int newWidth = pin.width + aboutHalf;
      pin.maxOffshift = newWidth;
      pin.currentOffshift = pin.width;

      // Width is now hoverBarWidth.
      pin.setWidth(hoverBarWidth + "px");

      // Looks better to immediately hide (Says the programmer).
      setPanelPos(0);
      pin.currentOffshift = 0;

      // clean up state.
      pin.hide();
    }

    /**
     * Go into pinned in place model
     */
    protected void becomePinned() {
      // The master width needs to be readjusted back to it's original size.
      if (pin.isAttached()) {
        pin.refreshWidth();
      }
      DOM.setStyleAttribute(mover, "left", "0px");
      pin.state.currentState = State.PINNED;
    }

    protected void setPanelPos(int pos) {
      DOM.setStyleAttribute(mover, "left", pos - pin.width + "px");
    }
  }

  /**
   * Current {@link PinnedPanel} state. TODO(ECC) change to enumeration once 1.5
   * is released.
   */
  private static class State {
    static int WILL_HIDE = 1;
    static int HIDING = 2;
    static int IS_HIDDEN = 3;
    static int WILL_SHOW = -1;
    static int SHOWING = -2;
    static int IS_SHOWN = -3;
    static int PINNED = -1000;
    int currentState;

    public boolean shouldHide() {
      return (currentState < 0);
    }

    public boolean shouldShow() {
      return currentState > 0;
    }
  }

  /**
   * Pause between each interval.
   */
  private static int OVERLAY_SPEED = 2;

  /**
   * Number of intervals used to display panel.
   */
  private static float TIME_TO_SLIDE = 200;

  /**
   * Minimum increment change per slide.
   */
  private static int MIN_SLIDE_STEP = 20;

  /**
   * How many milliseconds to delay a hover event before executing it.
   */
  private static final int DELAY_MILLI = 400;

  /**
   * Default style name.
   */
  private static final String DEFAULT_STYLENAME = "gwt-PinnedPanel";
  private ShowingTimer overlayTimer = new ShowingTimer();
  private HidingTimer hidingTimer = new HidingTimer();
  private DelayShow delayedShow = new DelayShow();
  private DelayHide delayedHide = new DelayHide();
  private State state = new State();
  private PinnedPanelImpl impl = new PinnedPanelImpl();
  private int width;
  private int maxOffshift;
  private int currentOffshift;
  private Panel mover;
  private SimplePanel hoverContainer;
  private ToggleButton pinnedToggle;
  private AbsolutePanel master;
  private ChangeListenerCollection changeListeners =
      new ChangeListenerCollection();

  /**
   * Constructor.
   *
   * @param width width of panel
   * @param pinnedToggle toggle for pinned state
   * @param contents contents to be displayed
   */
  public PinnedPanel(int width, final ToggleButton pinnedToggle, Widget contents) {
    this(width, pinnedToggle, contents, new HTML());
  }

  /**
   * Constructor.
   *
   * @param width width of panel
   * @param pinnedToggle toggle for pinned state
   * @param contents contents to be displayed
   * @param hoverBar hover bar
   */
  public PinnedPanel(int width, final ToggleButton pinnedToggle,
      Widget contents, Widget hoverBar) {

    // Create the composite widget.
    master = new AbsolutePanel() {
      {
        sinkEvents(Event.ONMOUSEOUT | Event.ONMOUSEOVER);
      }

      public void onBrowserEvent(Event event) {
        if (!PinnedPanel.this.pinnedToggle.isDown()) {
          switch (DOM.eventGetType(event)) {
            case Event.ONMOUSEOUT:
              Element to = DOM.eventGetToElement(event);
              if (state.currentState == State.WILL_SHOW) {
                state.currentState = State.HIDING;
                delayedShow.cancel();
                break;
              }
            
              if (to == null || (!DOM.isOrHasChild(this.getElement(), to))) {
                delayedHide.activate();
                break;
             
              break;
            case Event.ONMOUSEOVER:
              if ((state.shouldShow())) {
                if (state.currentState == State.WILL_HIDE) {
                  delayedHide.cancel();
                  state.currentState = State.SHOWING;
                } else {

                  delayedShow.activate();
                }
              }
              break;
          }
        }

        super.onBrowserEvent(event);
      }
    };

    DOM.setStyleAttribute(master.getElement(), "overflow", "visible");
    initWidget(master);
    setStyleName(DEFAULT_STYLENAME);
    master.setWidth(width + "px");
    // Create hovering container.
    hoverContainer = new SimplePanel();
    hoverContainer.setWidget(hoverBar);
    hoverContainer.setStyleName("hover-bar");
    master.add(hoverContainer, 0, 0);

    // Create the contents container.
    mover = new SimplePanel();
    mover.add(contents);
    contents.addStyleName("content");
    mover.setStyleName("mover");

    mover.setWidth(width + "px");
    master.add(mover, 0, 0);

    // Process the toggle.
    this.pinnedToggle = pinnedToggle;
    pinnedToggle.addStyleName("toggle");
    pinnedToggle.setDown(true);
    pinnedToggle.addClickListener(new ClickListener() {

      public void onClick(Widget sender) {
        setPinned(PinnedPanel.this.pinnedToggle.isDown());
      }
    });

    impl.setPinnedPanel(this);
    state.currentState = State.PINNED;
  }

  public void addChangeListener(ChangeListener listener) {
    changeListeners.add(listener);
  }

  public ToggleButton getSwitchButton() {
    return pinnedToggle;
  }

  /**
   * Is the panel pinned?
   */
  public boolean isPinned() {
    return state.currentState == State.PINNED;
  }

  public void removeChangeListener(ChangeListener listener) {
    changeListeners.remove(listener);
  }

  protected void hide() {
    state.currentState = State.HIDING;
    overlayTimer.cancel();
    hidingTimer.cancel();
    hidingTimer.started = System.currentTimeMillis();
    hidingTimer.run();
  }

  /**
   * This method is called immediately after a widget becomes attached to the
   * browser's document.
   */
  protected void onLoad() {
    refreshWidth();
  }

  protected void show() {
    state.currentState = State.SHOWING;

    overlayTimer.cancel();
    hidingTimer.cancel();
    overlayTimer.started = System.currentTimeMillis();
    overlayTimer.run();
  }

  private void refreshWidth() {
    // Now include borders into master.
    width = mover.getOffsetWidth();
    master.setWidth(width + "px");
  }

  private void setPinned(boolean pinned) {
    if (isPinned() == pinned) {
      return;
    }
    pinnedToggle.setDown(pinned);
    if (pinned) {
      impl.becomePinned();
    } else {
      impl.becomeOverlay();
    }
    changeListeners.fireChange(this);
  }
}
TOP

Related Classes of com.google.gwt.widgetideas.client.PinnedPanel$State

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.