Alexander Wels has uploaded a new change for review. Change subject: webadmin: main tab bar scrollable ......................................................................
webadmin: main tab bar scrollable - Make the main tab bar scrollable so we can resize the screen to be smaller. Change-Id: I63dddb3c0026ea3a5c13c3d18daebd02e13b1043 Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=818051 Signed-off-by: Alexander Wels <[email protected]> --- M frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/HeaderView.java M frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/HeaderView.ui.xml A frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/tab/ScrollableTabBar.java A frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/tab/ScrollableTabBar.ui.xml 4 files changed, 287 insertions(+), 9 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/16/21716/1 diff --git a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/HeaderView.java b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/HeaderView.java index 1276718..4f875e4 100644 --- a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/HeaderView.java +++ b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/HeaderView.java @@ -6,6 +6,7 @@ import org.ovirt.engine.ui.webadmin.ApplicationConstants; import org.ovirt.engine.ui.webadmin.ApplicationDynamicMessages; import org.ovirt.engine.ui.webadmin.section.main.presenter.HeaderPresenterWidget; +import org.ovirt.engine.ui.webadmin.widget.tab.ScrollableTabBar; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style.Unit; @@ -15,7 +16,6 @@ import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Anchor; -import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.InlineLabel; import com.google.gwt.user.client.ui.IsWidget; @@ -67,7 +67,7 @@ HTMLPanel mainTabBarPanel; @UiField - FlowPanel mainTabContainer; + ScrollableTabBar mainTabContainer; @UiField HTMLPanel feedbackImagePanel; @@ -114,7 +114,7 @@ @Override public void removeTabWidget(Widget tabWidget) { - mainTabContainer.getElement().removeChild(tabWidget.getElement()); + mainTabContainer.remove(tabWidget); } @Override diff --git a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/HeaderView.ui.xml b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/HeaderView.ui.xml index e895ff2..a12deee 100644 --- a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/HeaderView.ui.xml +++ b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/section/main/view/HeaderView.ui.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent"> -<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"> +<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui" + xmlns:ovirt="urn:import:org.ovirt.engine.ui.webadmin.widget.tab"> <ui:with field='constants' type='org.ovirt.engine.ui.webadmin.ApplicationConstants' /> @@ -52,10 +53,6 @@ height: 28px; } - .mainTabContainer { - min-width: 800px; - } - .headerLabelStyle { font-weight: bold; color: white; @@ -104,7 +101,7 @@ <g:SimplePanel ui:field="searchPanelContainer" addStyleNames="{style.searchPanel}" /> <g:HTMLPanel ui:field="mainTabBarPanel" addStyleNames="{style.mainTabBar}"> - <g:FlowPanel ui:field="mainTabContainer" addStyleNames="{style.mainTabContainer}"/> + <ovirt:ScrollableTabBar ui:field="mainTabContainer" /> <div style="clear: both;" /> </g:HTMLPanel> </g:HTMLPanel> diff --git a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/tab/ScrollableTabBar.java b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/tab/ScrollableTabBar.java new file mode 100644 index 0000000..2f4f287 --- /dev/null +++ b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/tab/ScrollableTabBar.java @@ -0,0 +1,249 @@ +package org.ovirt.engine.ui.webadmin.widget.tab; + +import com.google.gwt.core.client.GWT; +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.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.FocusPanel; +import com.google.gwt.user.client.ui.Widget; + +public class ScrollableTabBar extends Composite { + interface WidgetUiBinder extends UiBinder<Widget, ScrollableTabBar> { + WidgetUiBinder uiBinder = GWT.create(WidgetUiBinder.class); + } + +// private static final String SCROLL_BUTTON_STYLE = "tab-scroll-button"; //$NON-NLS-1$ + private static final int SCROLL_INTERVAL = 60; + private static final String MIN_WIDTH_STYLE = "minWidth"; //$NON-NLS-1$ + private static final String MAX_WIDTH_STYLE = "maxWidth"; //$NON-NLS-1$ + + /** + * The tab bar. + */ + @UiField + FlowPanel widgetBar; + + @UiField + FlowPanel scrollPanel; + + /** + * The left scroll button. + */ + @UiField + FocusPanel scrollLeftButton; + /** + * The right scroll button. + */ + @UiField + FocusPanel scrollRightButton; + + public ScrollableTabBar() { + super(); + initWidget(WidgetUiBinder.uiBinder.createAndBindUi(this)); + initScrollButtons(); + //Since this is singleton, don't need to worry about leaking handlers + Window.addResizeHandler(new ResizeHandler() { + @Override + public void onResize(ResizeEvent resizeEvent) { + showScrollButtons(); + } + }); + } + + public void insert(Widget tabWidget, int index) { + widgetBar.insert(tabWidget, index); + recalculateWidgetBarMinWidth(); + showScrollButtons(); + } + + public boolean remove(Widget tabWidget) { + boolean result = widgetBar.remove(tabWidget); + recalculateWidgetBarMinWidth(); + showScrollButtons(); + return result; + } + + private void recalculateWidgetBarMinWidth() { + //Set the minimum width. + widgetBar.getElement().getStyle().setProperty(MIN_WIDTH_STYLE, getWidgetMinWidthNeeded(), Unit.PX); + } + + private int getWidgetMinWidthNeeded() { + int minWidth = 0; + if (widgetBar.getWidgetCount() > 0) { + for(int i = 0; i < widgetBar.getWidgetCount(); i++) { + Widget widget = widgetBar.getWidget(i); + if(widget.isVisible()) { + minWidth += widget.getElement().getOffsetWidth(); + } + } + } + return minWidth; + } + private void recalculateScrollPanelMaxWidth() { + int minWidgetBarWidth = Math.max(getMaxWidth(), getWidgetMinWidthNeeded()); + widgetBar.getElement().getStyle().setProperty("width", minWidgetBarWidth + 15, Unit.PX); //$NON-NLS-1$ + scrollPanel.getElement().getStyle().setProperty(MAX_WIDTH_STYLE, getMaxWidth(), Unit.PX); + } + + private int getMaxWidth() { + int leftArrowWidth = scrollLeftButton.isVisible() ? scrollLeftButton.getWidget().getOffsetWidth() : 0; + int rightArrowWidth = scrollRightButton.isVisible() ? scrollRightButton.getWidget().getOffsetWidth() : 0; + return this.getElement().getOffsetWidth() - leftArrowWidth - rightArrowWidth; + } + + @Override + public void onAttach() { + Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { + + @Override + public void execute() { + recalculateWidgetBarMinWidth(); + recalculateScrollPanelMaxWidth(); + recalculateWidgetBarMinWidth(); + } + }); + } + + /** + * Create and attach the scroll button images with a click handler + */ + private void initScrollButtons() + { + +// scrollLeftButton.setStyleName(SCROLL_BUTTON_STYLE); +// buttonContainer.insert(scrollLeftButton, 0); +// buttonContainer.setWidgetTopHeight(scrollLeftButton, 0, Unit.PX, scrollLeftButtonImage.getHeight(), Unit.PX); +// buttonContainer.setWidgetLeftWidth(scrollLeftButton, 0, Unit.PX, leftArrowWidth, Unit.PX); + + scrollLeftButton.addDomHandler(createScrollClickHandler(SCROLL_INTERVAL), ClickEvent.getType()); + scrollLeftButton.setVisible(false); + +// scrollRightButton.setStyleName(SCROLL_BUTTON_STYLE); +// buttonContainer.insert(scrollRightButton, 1); +// buttonContainer.setWidgetTopHeight(scrollRightButton, 0, Unit.PX, scrollRightButtonImage.getHeight(), Unit.PX); +// buttonContainer.setWidgetRightWidth(scrollRightButton, 0, Unit.PX, rightArrowWidth, Unit.PX); + + scrollRightButton.addDomHandler(createScrollClickHandler(-SCROLL_INTERVAL), ClickEvent.getType()); + scrollRightButton.setVisible(false); + +// Element parent = tabBar.getElement().getParentElement().cast(); +// parent.getStyle().setMarginLeft(leftArrowWidth, Unit.PX); +// parent.getStyle().setMarginRight(rightArrowWidth, Unit.PX); + scrollTo(0); + } + + private void showScrollButtons() { + // 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() { + recalculateScrollPanelMaxWidth(); + 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 ClickHandler createScrollClickHandler(final int diff) { + return new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + adjustScroll(diff); + } + }; + } + + private boolean isScrollingNecessary() { + int minWidth = getWidgetMinWidthNeeded(); + return minWidth > 0 && getMaxWidth() > 0 && getMaxWidth() <= minWidth; + } + + private void adjustScroll(int diff) { + Widget lastTab = getLastTab(); + if (lastTab == null) { + return; + } + + int newLeft = parsePosition(widgetBar.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); + } + } + + private void scrollTo(int pos) { + widgetBar.getElement().getStyle().setLeft(pos, Unit.PX); + } + + private Widget getLastTab() { + Widget result = null; + if (widgetBar.getWidgetCount() > 0) { + for(int i = widgetBar.getWidgetCount() - 1; i > 1; i--) { + Widget tab = widgetBar.getWidget(i); + if(tab.isVisible()) { + result = tab; + break; + } + } + } + return result; + } + + private 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; + } + + private int getRightPosition(Widget widget) { + return widget.getElement().getOffsetLeft() + widget.getElement().getOffsetWidth(); + } + + private int getTabBarWidth() { + return widgetBar.getElement().getParentElement().getClientWidth(); + } +} diff --git a/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/tab/ScrollableTabBar.ui.xml b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/tab/ScrollableTabBar.ui.xml new file mode 100644 index 0000000..3284358 --- /dev/null +++ b/frontend/webadmin/modules/webadmin/src/main/java/org/ovirt/engine/ui/webadmin/widget/tab/ScrollableTabBar.ui.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent"> +<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"> + <ui:with field='resources' type='org.ovirt.engine.ui.common.CommonApplicationResources' /> + + <ui:style> + .scrollButton { + float: left; + } + .scrollPanel { + float: left; + overflow: hidden; + } + .widgetBar { + overflow-y: scroll; + } + </ui:style> + + <g:HTMLPanel> + <g:FocusPanel ui:field="scrollLeftButton" addStyleNames="{style.scrollButton}"> + <g:Image resource='{resources.refreshButtonImage}' /> + </g:FocusPanel> + <g:FlowPanel ui:field="scrollPanel" addStyleNames="{style.scrollPanel}"> + <g:FlowPanel ui:field="widgetBar" addStyleNames="{style.widgetBar}"> + </g:FlowPanel> + </g:FlowPanel> + <g:FocusPanel ui:field="scrollRightButton" addStyleNames="{style.scrollButton}"> + <g:Image resource='{resources.refreshButtonImage}' /> + </g:FocusPanel> + </g:HTMLPanel> + +</ui:UiBinder> -- To view, visit http://gerrit.ovirt.org/21716 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I63dddb3c0026ea3a5c13c3d18daebd02e13b1043 Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Alexander Wels <[email protected]> _______________________________________________ Engine-patches mailing list [email protected] http://lists.ovirt.org/mailman/listinfo/engine-patches
