/*
* Copyright 2011 cruxframework.org.
*
* 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 org.cruxframework.crux.smartfaces.client.rollingpanel;
import org.cruxframework.crux.core.client.screen.Screen;
import org.cruxframework.crux.smartfaces.client.backbone.common.FacesBackboneResourcesCommon;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.RepeatingCommand;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.event.logical.shared.AttachEvent;
import com.google.gwt.event.logical.shared.AttachEvent.Handler;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
/**
* @author Thiago da Rosa de Bustamante
*
*/
class RollingPanelNoTouchImpl extends Composite implements RollingPanel.PanelImplementation
{
private static final String NEXT_STYLE_NAME = "faces-RollingPanel-next";
private static final String PREVIOUS_STYLE_NAME = "faces-RollingPanel-previous";
private static final String NEXT_PANEL_STYLE_NAME = "faces-RollingPanel-nextPanel";
private static final String PREVIOUS_PANEL_STYLE_NAME = "faces-RollingPanel-previousPanel";
private static final String BODY_STYLE_NAME = "faces-RollingPanel-body";
private String nextButtonStyleName;
private String previousButtonStyleName;
private String bodyStyleName;
protected FlowPanel itemsPanel;
protected FlowPanel layoutPanel;
private Button nextButton = null;
private Button previousButton = null;
private ScrollPanel itemsScrollPanel;
private boolean scrollToAddedWidgets = false;
private SimplePanel previousButtonPanel;
private SimplePanel nextButtonPanel;
public RollingPanelNoTouchImpl()
{
FacesBackboneResourcesCommon.INSTANCE.css().ensureInjected();
this.layoutPanel = new FlowPanel();
createPreviousButton();
createBodyPanel();
createNextButton();
initWidget(layoutPanel);
dynamicFixHeight();
handleWindowResize();
maybeShowNavigationButtons();
}
private void dynamicFixHeight()
{
Scheduler.get().scheduleDeferred(new ScheduledCommand()
{
@Override
public void execute()
{
layoutPanel.setHeight("100%");
}
});
}
@Override
public void setStyleName(String style, boolean add)
{
super.setStyleName(style, add);
if (!add)
{
addStyleName(FacesBackboneResourcesCommon.INSTANCE.css().flexBoxHorizontalContainer());
}
}
@Override
public void setStyleName(String style)
{
super.setStyleName(style);
addStyleName(FacesBackboneResourcesCommon.INSTANCE.css().flexBoxHorizontalContainer());
}
/**
* @param child
*/
public void add(final Widget child)
{
this.itemsPanel.add(child);
maybeShowNavigationButtons();
if (scrollToAddedWidgets)
{
Scheduler.get().scheduleDeferred(new ScheduledCommand()
{
public void execute()
{
scrollToWidget(child);
}
});
}
}
/**
*
*/
public void clear()
{
this.itemsPanel.clear();
maybeShowNavigationButtons();
}
/**
* @return
*/
public int getScrollPosition()
{
return itemsScrollPanel.getElement().getScrollLeft();
}
@Override
public Widget getWidget(int i)
{
return itemsPanel.getWidget(i);
}
@Override
public int getWidgetCount()
{
return itemsPanel.getWidgetCount();
}
@Override
public int getWidgetIndex(Widget child)
{
return itemsPanel.getWidgetIndex(child);
}
@Override
public void insert(final Widget widget, int i)
{
itemsPanel.insert(widget, i);
maybeShowNavigationButtons();
if (scrollToAddedWidgets)
{
Scheduler.get().scheduleDeferred(new ScheduledCommand()
{
public void execute()
{
scrollToWidget(widget);
}
});
}
}
/**
* @return
*/
public boolean isScrollToAddedWidgets()
{
return scrollToAddedWidgets;
}
@Override
public boolean remove(int index)
{
boolean ret = itemsPanel.remove(index);
maybeShowNavigationButtons();
return ret;
}
/**
* @param toRemove
*/
public boolean remove(Widget toRemove)
{
boolean removed = itemsPanel.remove(toRemove);
maybeShowNavigationButtons();
return removed;
}
/**
* @param widget
*/
public void scrollToWidget(Widget widget)
{
if (widget != null)
{
Element scroll = itemsScrollPanel.getElement();
Element item = widget.getElement();
if (itemsPanel.getOffsetWidth() > layoutPanel.getOffsetWidth())
{
int realOffset = 0;
int itemOffsetWidth = item.getOffsetWidth();
while (item != null && item != scroll)
{
realOffset += item.getOffsetLeft();
item = item.getParentElement();
}
int scrollLeft = getScrollPosition();
int scrollOffsetWidth = scroll.getOffsetWidth();
int right = realOffset + itemOffsetWidth;
int visibleWidth = scrollLeft + scrollOffsetWidth;
if (realOffset < scrollLeft)
{
setScrollPosition(realOffset);
}
else if (right > visibleWidth)
{
setScrollPosition(scrollLeft + right - visibleWidth);
}
}
}
}
/**
* @param position
*/
public void setScrollPosition(int position)
{
if (position < 0)
{
position = 0;
}
else
{
int offsetWidth = itemsPanel.getOffsetWidth();
if (position > offsetWidth)
{
position = offsetWidth;
}
}
itemsScrollPanel.getElement().setPropertyInt("scrollLeft", position);
}
/**
* @param scrollToAddedWidgets
*/
public void setScrollToAddedWidgets(boolean scrollToAddedWidgets)
{
this.scrollToAddedWidgets = scrollToAddedWidgets;
}
protected void createPreviousButton()
{
NavButtonEvtHandler handler = new NavButtonEvtHandler(-20, -5);
previousButton = new Button();
previousButton.setText("<");
previousButton.setStyleName(PREVIOUS_STYLE_NAME);
previousButton.addMouseDownHandler(handler);
previousButton.addMouseUpHandler(handler);
previousButtonPanel = new SimplePanel();
previousButtonPanel.setStyleName(PREVIOUS_PANEL_STYLE_NAME);
previousButtonPanel.addStyleName(FacesBackboneResourcesCommon.INSTANCE.css().flexBoxFirstChild());
previousButtonPanel.add(previousButton);
layoutPanel.add(previousButtonPanel);
}
protected void createNextButton()
{
NavButtonEvtHandler handler = new NavButtonEvtHandler(20, 5);
nextButton = new Button();
nextButton.setText(">");
nextButton.setStyleName(NEXT_STYLE_NAME);
nextButton.addMouseDownHandler(handler);
nextButton.addMouseUpHandler(handler);
nextButtonPanel = new SimplePanel();
nextButtonPanel.setStyleName(NEXT_PANEL_STYLE_NAME);
nextButtonPanel.addStyleName(FacesBackboneResourcesCommon.INSTANCE.css().flexBoxThirdChild());
nextButtonPanel.add(nextButton);
layoutPanel.add(nextButtonPanel);
}
protected void createBodyPanel()
{
itemsScrollPanel = new ScrollPanel();
itemsScrollPanel.setStyleName(BODY_STYLE_NAME);
itemsScrollPanel.addStyleName(FacesBackboneResourcesCommon.INSTANCE.css().facesBackboneRollingPanelBody());
itemsPanel = new FlowPanel();
itemsPanel.setStyleName(FacesBackboneResourcesCommon.INSTANCE.css().flexBoxInlineContainer());
itemsScrollPanel.add(itemsPanel);
layoutPanel.add(itemsScrollPanel);
}
protected void checkNavigationButtons()
{
if (itemsPanel.getOffsetWidth() > layoutPanel.getOffsetWidth() - (nextButton.getOffsetWidth() + previousButton.getOffsetWidth()))
{
enableNavigationButtons();
}
else
{
disableNavigationButtons();
setScrollPosition(0);
}
}
protected void maybeShowNavigationButtons()
{
new Timer()
{
@Override
public void run()
{
checkNavigationButtons();
}
}.schedule(30);
}
protected void disableNavigationButtons()
{
previousButtonPanel.addStyleDependentName("-disabled");
nextButtonPanel.addStyleDependentName("-disabled");
}
protected void enableNavigationButtons()
{
previousButtonPanel.removeStyleDependentName("-disabled");
nextButtonPanel.removeStyleDependentName("-disabled");
}
protected void handleWindowResize()
{
addAttachHandler(new Handler()
{
HandlerRegistration registration;
@Override
public void onAttachOrDetach(AttachEvent event)
{
if (event.isAttached())
{
registration = Screen.addResizeHandler(new ResizeHandler()
{
public void onResize(ResizeEvent event)
{
checkNavigationButtons();
}
});
}
else if (registration != null)
{
registration.removeHandler();
registration = null;
}
}
});
}
/**
* @author Thiago da Rosa de Bustamante -
*
*/
class NavButtonEvtHandler implements MouseDownHandler, MouseUpHandler
{
private int adjust;
private boolean buttonPressed = false;
private int delta;
private int incrementalAdjust;
private int originalIncrementalAdjust;
NavButtonEvtHandler(int adjust, int incrementalAdjust)
{
this.adjust = adjust;
this.incrementalAdjust = incrementalAdjust;
this.originalIncrementalAdjust = incrementalAdjust;
this.delta = incrementalAdjust / 4;
}
public void onMouseDown(MouseDownEvent event)
{
buttonPressed = true;
adjustScrollPosition(adjust);
Scheduler.get().scheduleFixedDelay(new RepeatingCommand()
{
public boolean execute()
{
if (buttonPressed)
{
adjustScrollPosition(incrementalAdjust+=delta);
}
return buttonPressed;
}
}, 50);
}
public void onMouseUp(MouseUpEvent event)
{
buttonPressed = false;
incrementalAdjust = originalIncrementalAdjust;
}
/**
* @param adjust
*/
protected void adjustScrollPosition(int adjust)
{
int position = getScrollPosition() + adjust;
setScrollPosition(position);
}
}
/**
* @param nextButtonStyleName
*/
public void setNextButtonStyleName(String nextButtonStyleName)
{
this.nextButtonStyleName = nextButtonStyleName;
this.nextButton.setStyleName(this.nextButtonStyleName);
}
/**
* @param previousButtonStyleName
*/
public void setPreviousButtonStyleName(String previousButtonStyleName)
{
this.previousButtonStyleName = previousButtonStyleName;
this.previousButton.setStyleName(this.previousButtonStyleName);
}
/**
* @param bodyStyleName the bodyStyleName to set
*/
public void setBodyStyleName(String bodyStyleName)
{
this.bodyStyleName = bodyStyleName;
this.itemsScrollPanel.setStyleName(this.bodyStyleName);
}
/**
* @return the bodyStyleName
*/
public String getBodyStyleName()
{
return bodyStyleName;
}
/**
* @return the nextButtonStyleName
*/
public String getNextButtonStyleName()
{
return nextButtonStyleName;
}
/**
* @return the previousButtonStyleName
*/
public String getPreviousButtonStyleName()
{
return previousButtonStyleName;
}
}