An update: I prefer to have the scroll buttons on each side of the tabs, and I reduced the
tab bar so it is not under the buttons.
I put the images in divs (SimplePanel) for further CSS styling (adding cursor: pointer;
for example).
And I fixed a bug in my previous version: when the bar is scrolled to the right, and the
window is widened, the gap on the left was not closed and we could no longer scroll.
Here is the improved version:
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
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.resources.client.ImageResource;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.LayoutPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.TabLayoutPanel;
import com.google.gwt.user.client.ui.Widget;
/**
* A {@link TabLayoutPanel} that shows scroll buttons if necessary.
* https://groups.google.com/forum/?fromgroups=#!topic/google-web-toolkit/wN8lLU23wPA
*/
public class ScrollableTabLayoutPanel extends TabLayoutPanel
{
private static final String SCROLL_BUTTON_STYLE = "tab-scroll-button";
private static final int SCROLL_INTERVAL = 60;
private LayoutPanel panel;
private FlowPanel tabBar;
private HandlerRegistration windowResizeHandler;
private SimplePanel scrollLeftButton;
private SimplePanel scrollRightButton;
private ImageResource leftArrowImage;
private ImageResource rightArrowImage;
public ScrollableTabLayoutPanel(double barHeight, Unit barUnit,
ImageResource leftArrowImage, ImageResource rightArrowImage)
{
super(barHeight, barUnit);
this.leftArrowImage = leftArrowImage;
this.rightArrowImage = rightArrowImage;
// The main widget wrapped by this composite, which is a LayoutPanel with the tab
bar & the tab content
panel = (LayoutPanel) getWidget();
// Find the tab bar, which is the first flow panel in the LayoutPanel
for (int i = 0; i < panel.getWidgetCount(); i++)
{
Widget widget = panel.getWidget(i);
if (widget instanceof FlowPanel)
{
tabBar = (FlowPanel) widget;
break;
}
}
initScrollButtons();
}
@Override
public void insert(Widget child, Widget tab, int beforeIndex)
{
super.insert(child, tab, beforeIndex);
showScrollButtonsIfNecessary();
}
@Override
public boolean remove(int index)
{
boolean b = super.remove(index);
showScrollButtonsIfNecessary();
return b;
}
@Override
protected void onLoad()
{
super.onLoad();
if (windowResizeHandler == null)
{
windowResizeHandler = Window.addResizeHandler(new ResizeHandler()
{
@Override
public void onResize(ResizeEvent event)
{
showScrollButtonsIfNecessary();
}
});
}
}
@Override
protected void onUnload()
{
super.onUnload();
if (windowResizeHandler != null)
{
windowResizeHandler.removeHandler();
windowResizeHandler = null;
}
}
private ClickHandler createScrollClickHandler(final int diff)
{
return new ClickHandler()
{
@Override
public void onClick(ClickEvent event)
{
adjustScroll(diff);
}
};
}
private void adjustScroll(int diff)
{
Widget lastTab = getLastTab();
if (lastTab == null)
return;
int newLeft = parsePosition(tabBar.getElement().getStyle().getLeft()) + diff;
int rightOfLastTab = getRightPosition(lastTab);
// Don't scroll for a positive newLeft
if (newLeft <= 0)
{
// If we are about to scroll too far away from the right border, adjust back
int gap = rightOfLastTab - getTabBarWidth();
if (gap < -newLeft)
{
newLeft += -newLeft - gap;
}
scrollTo(newLeft);
}
else
{
scrollTo(0);
}
}
/**
* Create and attach the scroll button images with a click handler
*/
private void initScrollButtons()
{
Image scrollLeftButtonImage = new Image(leftArrowImage);
Image scrollRightButtonImage = new Image(rightArrowImage);
int leftArrowWidth = scrollLeftButtonImage.getWidth();
int rightArrowWidth = scrollRightButtonImage.getWidth();
scrollLeftButton = new SimplePanel(scrollLeftButtonImage);
scrollLeftButton.setStyleName(SCROLL_BUTTON_STYLE);
scrollLeftButton.setWidget(scrollLeftButtonImage);
panel.insert(scrollLeftButton, 0);
panel.setWidgetTopHeight(scrollLeftButton, 0, Unit.PX,
scrollLeftButtonImage.getHeight(), Unit.PX);
panel.setWidgetLeftWidth(scrollLeftButton, 0, Unit.PX, leftArrowWidth, Unit.PX);
scrollLeftButtonImage.addClickHandler(createScrollClickHandler(SCROLL_INTERVAL));
scrollLeftButton.setVisible(false);
scrollRightButton = new SimplePanel(scrollRightButtonImage);
scrollRightButton.setStyleName(SCROLL_BUTTON_STYLE);
scrollRightButton.setWidget(scrollRightButtonImage);
panel.insert(scrollRightButton, 1);
panel.setWidgetTopHeight(scrollRightButton, 0, Unit.PX,
scrollRightButtonImage.getHeight(), Unit.PX);
panel.setWidgetRightWidth(scrollRightButton, 0, Unit.PX, rightArrowWidth, Unit.PX);
scrollRightButtonImage.addClickHandler(createScrollClickHandler(-SCROLL_INTERVAL));
scrollRightButton.setVisible(false);
Element parent = tabBar.getElement().getParentElement().cast();
parent.getStyle().setMarginLeft(leftArrowWidth, Unit.PX);
parent.getStyle().setMarginRight(rightArrowWidth, Unit.PX);
}
private void showScrollButtonsIfNecessary()
{
// Defer size calculations until sizes are available.
// When calculating immediately after add(), all size methods return zero.
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand()
{
@Override
public void execute()
{
boolean isScrolling = isScrollingNecessary();
if (scrollRightButton.isVisible())
{
if (!isScrolling)
{
// The scroll buttons are being hidden, reset the scroll position
to zero to avoid
// having tabs starting in the middle of the window!
scrollTo(0);
}
else
{
// Resizing or adding / removing tabs, recompute the scroll
adjustScroll(0);
}
}
scrollRightButton.setVisible(isScrolling);
scrollLeftButton.setVisible(isScrolling);
}
});
}
private void scrollTo(int pos)
{
tabBar.getElement().getStyle().setLeft(pos, Unit.PX);
}
private boolean isScrollingNecessary()
{
Widget lastTab = getLastTab();
return lastTab != null && getRightPosition(lastTab) > getTabBarWidth();
}
private int getRightPosition(Widget widget)
{
return widget.getElement().getOffsetLeft() + widget.getElement().getOffsetWidth();
}
private int getTabBarWidth()
{
return tabBar.getElement().getParentElement().getClientWidth();
}
private Widget getLastTab()
{
if (tabBar.getWidgetCount() == 0)
return null;
return tabBar.getWidget(tabBar.getWidgetCount() - 1);
}
private static int parsePosition(String positionString)
{
int position = 0;
int sign = -1;
int i = 0;
if (positionString.charAt(0) == '-')
{
sign = -1;
i++;
}
for (; i < positionString.length(); i++)
{
char c = positionString.charAt(i);
if (c < '0' || c > '9')
break;
position = 10 * position + c - '0';
}
return sign * position;
}
}
Again, kudos to those having provided the code on which I based this version. :-)
Again, simple recipe: just use ScrollableTabLayoutPanel where you would use
TabLayoutPanel, by providing it the two button image resources.
--
Philippe Lhoste
-- (near) Paris -- France
-- http://Phi.Lho.free.fr
-- -- -- -- -- -- -- -- -- -- -- -- -- --
--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscribe@googlegroups.com.
To post to this group, send email to google-web-toolkit@googlegroups.com.
Visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
No comments:
Post a Comment