Last active
September 19, 2018 02:08
-
-
Save branflake2267/44025882d6100f20932cace1f28ab1a8 to your computer and use it in GitHub Desktop.
GXT 4.0.3 workqround for HBoxLayoutContainer UiBinder issue. 'child' works again with this workaround. This adds a "sibling" tag to fix it. This will be fixed in 4.0.4
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.sencha.gxt.widget.core.client.container; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.logging.Logger; | |
import com.google.gwt.core.client.GWT; | |
import com.google.gwt.core.client.Scheduler; | |
import com.google.gwt.core.client.Scheduler.ScheduledCommand; | |
import com.google.gwt.dom.client.Style.Unit; | |
import com.google.gwt.event.logical.shared.SelectionEvent; | |
import com.google.gwt.event.logical.shared.SelectionHandler; | |
import com.google.gwt.event.logical.shared.ValueChangeEvent; | |
import com.google.gwt.event.logical.shared.ValueChangeHandler; | |
import com.google.gwt.event.shared.HandlerRegistration; | |
import com.google.gwt.resources.client.ImageResource; | |
import com.google.gwt.safehtml.shared.SimpleHtmlSanitizer; | |
import com.google.gwt.uibinder.client.UiChild; | |
import com.google.gwt.user.client.ui.HasWidgets; | |
import com.google.gwt.user.client.ui.IsWidget; | |
import com.google.gwt.user.client.ui.Widget; | |
import com.sencha.gxt.core.client.GXTLogConfiguration; | |
import com.sencha.gxt.core.client.Style; | |
import com.sencha.gxt.core.client.dom.XElement; | |
import com.sencha.gxt.core.client.resources.CommonStyles; | |
import com.sencha.gxt.core.client.util.Margins; | |
import com.sencha.gxt.core.client.util.Size; | |
import com.sencha.gxt.core.client.util.Util; | |
import com.sencha.gxt.core.shared.event.GroupingHandlerRegistration; | |
import com.sencha.gxt.widget.core.client.Component; | |
import com.sencha.gxt.widget.core.client.button.ButtonGroup; | |
import com.sencha.gxt.widget.core.client.button.SplitButton; | |
import com.sencha.gxt.widget.core.client.button.TextButton; | |
import com.sencha.gxt.widget.core.client.button.ToggleButton; | |
import com.sencha.gxt.widget.core.client.event.BeforeShowEvent; | |
import com.sencha.gxt.widget.core.client.event.BeforeShowEvent.BeforeShowHandler; | |
import com.sencha.gxt.widget.core.client.event.CheckChangeEvent; | |
import com.sencha.gxt.widget.core.client.event.CheckChangeEvent.CheckChangeHandler; | |
import com.sencha.gxt.widget.core.client.event.OverflowEvent; | |
import com.sencha.gxt.widget.core.client.event.OverflowEvent.HasOverflowHandlers; | |
import com.sencha.gxt.widget.core.client.event.OverflowEvent.OverflowHandler; | |
import com.sencha.gxt.widget.core.client.event.SelectEvent; | |
import com.sencha.gxt.widget.core.client.menu.CheckMenuItem; | |
import com.sencha.gxt.widget.core.client.menu.ColorMenu; | |
import com.sencha.gxt.widget.core.client.menu.HeaderMenuItem; | |
import com.sencha.gxt.widget.core.client.menu.Item; | |
import com.sencha.gxt.widget.core.client.menu.Menu; | |
import com.sencha.gxt.widget.core.client.menu.MenuItem; | |
import com.sencha.gxt.widget.core.client.menu.SeparatorMenuItem; | |
import com.sencha.gxt.widget.core.client.toolbar.FillToolItem; | |
import com.sencha.gxt.widget.core.client.toolbar.LabelToolItem; | |
import com.sencha.gxt.widget.core.client.toolbar.SeparatorToolItem; | |
import com.sencha.gxt.widget.core.client.toolbar.ToolBar; | |
/** | |
* <p> | |
* A layout container for horizontal rows of widgets. Provides support for automatic overflow (i.e. when there are too | |
* many widgets to display in the available width -- see {@link #setEnableOverflow(boolean)}). | |
* </p> | |
* | |
* <p> | |
* Code Snippet: | |
* </p> | |
* | |
* <pre> | |
* <code> | |
* HBoxLayoutContainer c = new HBoxLayoutContainer(); | |
* c.setHBoxLayoutAlign(HBoxLayoutAlign.TOP); | |
* BoxLayoutData layoutData = new BoxLayoutData(new Margins(5, 0, 0, 5)); | |
* c.add(new TextButton("Button 1"), layoutData); | |
* c.add(new TextButton("Button 2"), layoutData); | |
* c.add(new TextButton("Button 3"), layoutData); | |
* Viewport v = new Viewport(); | |
* v.add(c); | |
* RootPanel.get().add(v); | |
* </code> | |
* </pre> | |
* | |
* @see ToolBar | |
*/ | |
public class HBoxLayoutContainer extends BoxLayoutContainer implements HasOverflowHandlers { | |
/** | |
* The vertical alignment of the horizontal widgets. | |
*/ | |
public enum HBoxLayoutAlign { | |
/** | |
* Children are aligned horizontally at the <b>bottom</b> side of the container. | |
*/ | |
BOTTOM, | |
/** | |
* Children are aligned horizontally at the <b>mid-height</b> of the container. | |
*/ | |
MIDDLE, | |
/** | |
* Children are stretched vertically to fill the height of the container. | |
*/ | |
STRETCH, | |
/** | |
* Children heights are set the size of the largest child's height. | |
*/ | |
STRETCHMAX, | |
/** | |
* Children are aligned horizontally at the <b>top</b> side of the container. | |
*/ | |
TOP | |
} | |
public interface HBoxLayoutContainerAppearance extends BoxLayoutContainerAppearance { | |
ImageResource moreIcon(); | |
String moreButtonStyle(); | |
} | |
/** | |
* Use this Component data attribute name to provide custom menu item text. | |
*/ | |
public static String PROVIDE_MENU_TEXT_DATA_KEY = "gxt-menutext"; | |
protected List<Widget> hiddens = new ArrayList<Widget>(); | |
protected boolean hasOverflow; | |
protected TextButton more; | |
protected Menu moreMenu; | |
protected HashMap<Integer, MenuItem> moreMenuItems; | |
protected GroupingHandlerRegistration handlerRegistration = new GroupingHandlerRegistration(); | |
protected boolean enableOverflow = true; | |
protected HBoxLayoutAlign hBoxLayoutAlign; | |
protected Map<Widget, Integer> loopWidthMap = new HashMap<Widget, Integer>(); | |
protected Map<Widget, Integer> loopHeightMap = new HashMap<Widget, Integer>(); | |
protected int triggerWidth = 35; | |
protected Map<Widget, Integer> widthMap = new HashMap<Widget, Integer>(); | |
protected boolean moreMenuEnableScrolling; | |
protected static Logger logger = Logger.getLogger(HBoxLayoutContainer.class.getName()); | |
/** | |
* Creates a new HBoxlayout. | |
*/ | |
public HBoxLayoutContainer() { | |
this(HBoxLayoutAlign.TOP); | |
} | |
/** | |
* Creates a new HBoxlayout. | |
* | |
* @param appearance the hbox appearance | |
*/ | |
public HBoxLayoutContainer(HBoxLayoutContainerAppearance appearance) { | |
this(HBoxLayoutAlign.TOP, appearance); | |
} | |
/** | |
* Creates a new HBoxlayout. | |
* | |
* @param align the horizontal alignment | |
*/ | |
public HBoxLayoutContainer(HBoxLayoutAlign align) { | |
this(align, GWT.<HBoxLayoutContainerAppearance>create(HBoxLayoutContainerAppearance.class)); | |
} | |
protected HBoxLayoutContainer(HBoxLayoutAlign align, HBoxLayoutContainerAppearance appearance) { | |
super(appearance); | |
setHBoxLayoutAlign(align); | |
} | |
@Override | |
public void add(IsWidget child) { | |
super.add(child); | |
} | |
/** | |
* Add a widget and a custom menu item to show when overlfow menu is displayed. | |
* <p> | |
* | |
* This caused a regression in 4.0.3, so a parameter was added. This has been deprecated. Change to | |
* {@link #addWithMenu(IsWidget, MenuItem)}. | |
* | |
* @param child the widget | |
* @param menuItem the menu item for the widget when it's not visible | |
* @param ignoreParam this has been added to fix a compiler regression in 4.0.3. | |
* @since 4.0.4 | |
*/ | |
@Deprecated | |
public void add(IsWidget child, MenuItem menuItem, Boolean ignoreParam) { | |
super.add(child); | |
addMenuItem(menuItem); | |
} | |
/** | |
* Add a widget and a custom menu item to show when overlfow menu is displayed. | |
* <p> | |
* | |
* This caused a regression in 4.0.3, so a parameter was added. This has been deprecated. Change to | |
* {@link #addWithMenu(Widget, MenuItem)}. | |
* | |
* @param child the widget | |
* @param menuItem the menu item for the widget when it's not visible | |
* @param ignoreParam this has been added to fix a compiler regression in 4.0.3. | |
* @since 4.0.4 | |
*/ | |
@Deprecated | |
public void add(Widget child, MenuItem menuItem, Boolean ignoreParam) { | |
super.add(child); | |
addMenuItem(menuItem); | |
} | |
/** | |
* Add a widget. | |
* | |
* @param child the child to add. | |
*/ | |
@Override | |
public void add(Widget child) { | |
super.add(child); | |
} | |
/** | |
* Add a widget. | |
* | |
* In UiBinder use <container:child/> | |
* | |
* @param child the widget | |
* @param layoutData the layout data. | |
*/ | |
@UiChild(tagname = "child") | |
@Override | |
public void add(IsWidget child, BoxLayoutData layoutData) { | |
super.add(child, layoutData); | |
} | |
/** | |
* This was added to deal with the 4.0.3 regression. This covers those who changed to use sibling. | |
* | |
* Please use the <container:child/> for the children in uibinder. | |
* | |
* @param child the child to add | |
* @param layoutData the box layout data | |
* @since 4.0.4 | |
*/ | |
@UiChild(tagname = "sibling") | |
@Deprecated | |
public void addWithUiBinder(IsWidget child, BoxLayoutData layoutData) { | |
if (child != null) { | |
child.asWidget().setLayoutData(layoutData); | |
} | |
super.add(child); | |
} | |
/** | |
* Add a widget and a custom menu item to show when overlfow menu is displayed. | |
* <p> | |
* | |
* @param child the widget | |
* @param menuItem the menu item for the widget when it's not visible | |
* @since 4.0.4 | |
*/ | |
public void addWithMenu(IsWidget child, MenuItem menuItem) { | |
super.add(child); | |
addMenuItem(menuItem); | |
} | |
/** | |
* Add a widget and a custom menu item to show when overlfow menu is displayed. | |
* <p> | |
* | |
* @param child the widget | |
* @param menuItem the menu item for the widget when it's not visible | |
* @since 4.0.4 | |
*/ | |
public void addWithMenu(Widget child, MenuItem menuItem) { | |
super.add(child); | |
addMenuItem(menuItem); | |
} | |
/** | |
* Add a widget with layout data and a custom menu item to show when overlfow menu is displayed. | |
* <p> | |
* | |
* @param child the widget | |
* @param layoutData the sizing for the child | |
* @param menuItem the menu item when it's not visible | |
* @since 4.0.3 | |
*/ | |
public void add(IsWidget child, BoxLayoutData layoutData, MenuItem menuItem) { | |
super.add(child, layoutData); | |
addMenuItem(menuItem); | |
} | |
@Override | |
public void insert(Widget w, int beforeIndex) { | |
super.insert(w, beforeIndex); | |
// when adding in an hbox child, measure it, then a parent can calculate it's size. | |
if (isAttached()) { | |
forceLayout(); | |
} | |
} | |
@Override | |
public boolean remove(Widget child) { | |
boolean removed = super.remove(child); | |
// when adding in an hbox child, measure it, then a parent can calculate it's size. | |
if (isAttached()) { | |
forceLayout(); | |
} | |
return removed; | |
} | |
/** | |
* When the overflow menu is shown. | |
*/ | |
@Override | |
public HandlerRegistration addOverflowHandler(OverflowHandler handler) { | |
return addHandler(handler, OverflowEvent.getType()); | |
} | |
protected void addMenuItem(MenuItem menuItem) { | |
if (moreMenuItems == null) { | |
moreMenuItems = new HashMap<Integer, MenuItem>(); | |
} | |
int index = getWidgetCount() - 1; | |
moreMenuItems.put(index, menuItem); | |
} | |
/** | |
* Returns the horizontal layout appearance. | |
* | |
* @return the appearance | |
*/ | |
@Override | |
public HBoxLayoutContainerAppearance getAppearance() { | |
return (HBoxLayoutContainerAppearance) super.getAppearance(); | |
} | |
/** | |
* Returns the horizontal alignment. | |
* | |
* @return the horizontal alignment | |
*/ | |
public HBoxLayoutAlign getHBoxLayoutAlign() { | |
return hBoxLayoutAlign; | |
} | |
/** | |
* Returns true if overflow is enabled. | |
* | |
* @return the overflow state | |
*/ | |
public boolean isEnableOverflow() { | |
return enableOverflow; | |
} | |
/** | |
* True to show a drop down icon when the available width is less than the required width (defaults to true). | |
* | |
* @param enableOverflow true to enable overflow support | |
*/ | |
public void setEnableOverflow(boolean enableOverflow) { | |
this.enableOverflow = enableOverflow; | |
} | |
/** | |
* Sets the vertical alignment for child items (defaults to TOP). | |
* | |
* @param hBoxLayoutAlign the vertical alignment | |
*/ | |
public void setHBoxLayoutAlign(HBoxLayoutAlign hBoxLayoutAlign) { | |
this.hBoxLayoutAlign = hBoxLayoutAlign; | |
} | |
/** | |
* Add widget to overflow menu. | |
* | |
* @param menu the overflow menu | |
* @param w the widget that will get converted into the menu item | |
*/ | |
protected void addWidgetToMenu(Menu menu, Widget w) { | |
if (w instanceof SeparatorToolItem) { | |
addMenuItemToMoreMenuSeparatorItem(w, menu); | |
} else if (w instanceof SplitButton) { | |
addWidgetToMenuSplitButton(menu, w); | |
} else if (w instanceof TextButton) { | |
addWidgetToMenuTextButton(menu, w); | |
} else if (w instanceof ButtonGroup) { | |
addWidgetToMenuButtonGroup(menu, w); | |
} else if (w instanceof ToggleButton) { | |
addWidgetToMenuToggleButton(menu, w); | |
} else if (w instanceof LabelToolItem) { | |
addWidgetToMenuLabelToolItem(menu, w); | |
} | |
afterAddWidgetToMenu(menu); | |
} | |
/** | |
* @since 4.0.3 | |
*/ | |
protected void addMenuItemToMoreMenuSeparatorItem(Widget w, Menu menu) { | |
SeparatorMenuItem item = new SeparatorMenuItem(); | |
addMenuItemToMoreMenu(w, menu, item); | |
} | |
/** | |
* @since 4.0.3 | |
*/ | |
protected void addWidgetToMenuLabelToolItem(Menu menu, Widget w) { | |
final LabelToolItem lti = (LabelToolItem) w; | |
MenuItem item = new MenuItem(); | |
item.setHTML(lti.getLabel()); | |
addMenuItemToMoreMenu(w, menu, item); | |
} | |
/** | |
* @since 4.0.3 | |
*/ | |
protected void addMenuItemToMoreMenu(Widget w, Menu menu, Item item) { | |
menu.add(item); | |
} | |
/** | |
* @since 4.0.3 | |
*/ | |
protected void addWidgetToMenuToggleButton(Menu menu, Widget w) { | |
final ToggleButton b = (ToggleButton) w; | |
final CheckMenuItem item = new CheckMenuItem(b.getText()); | |
item.setItemId(b.getItemId()); | |
item.setChecked(b.getValue()); | |
item.setEnabled(b.isEnabled()); | |
if (b.getData(PROVIDE_MENU_TEXT_DATA_KEY) != null) { | |
item.setHTML(SimpleHtmlSanitizer.sanitizeHtml(b.getData(PROVIDE_MENU_TEXT_DATA_KEY).toString())); | |
} | |
handlerRegistration.add(item.addCheckChangeHandler(new CheckChangeHandler<CheckMenuItem>() { | |
@Override | |
public void onCheckChange(CheckChangeEvent<CheckMenuItem> event) { | |
// must pass true to cause value change event to fire | |
b.setValue(event.getItem().isChecked(), true); | |
b.fireEvent(new SelectEvent()); | |
} | |
})); | |
addMenuItemToMoreMenu(w, menu, item); | |
} | |
/** | |
* @since 4.0.3 | |
*/ | |
protected void addWidgetToMenuButtonGroup(Menu menu, Widget w) { | |
ButtonGroup buttonGroup = (ButtonGroup) w; | |
buttonGroup.setItemId(buttonGroup.getItemId()); | |
addMenuItemToMoreMenu(w, menu, new SeparatorMenuItem()); | |
addMenuItemToMoreMenu(w, menu, new HeaderMenuItem(buttonGroup.getHeading())); | |
Widget con = buttonGroup.getWidget(); | |
if (con != null && con instanceof HasWidgets) { | |
HasWidgets widgets = (HasWidgets) con; | |
Iterator<Widget> it = widgets.iterator(); | |
while (it.hasNext()) { | |
addWidgetToMenu(menu, it.next()); | |
} | |
} | |
addMenuItemToMoreMenu(w, menu, new SeparatorMenuItem()); | |
} | |
/** | |
* @since 4.0.3 | |
*/ | |
protected void addWidgetToMenuTextButton(Menu menu, Widget w) { | |
final TextButton textButton = (TextButton) w; | |
MenuItem item = new MenuItem(textButton.getText(), textButton.getIcon()); | |
item.setItemId(textButton.getItemId()); | |
if (textButton.getData(PROVIDE_MENU_TEXT_DATA_KEY) != null) { | |
item.setHTML(SimpleHtmlSanitizer.sanitizeHtml(textButton.getData(PROVIDE_MENU_TEXT_DATA_KEY).toString())); | |
} | |
if (textButton.getMenu() != null) { | |
item.setHideOnClick(false); | |
item.setSubMenu(textButton.getMenu()); | |
if (item.getSubMenu() instanceof ColorMenu) { | |
ColorMenu colorMenu = (ColorMenu) item.getSubMenu(); | |
handlerRegistration.add(colorMenu.getPalette().addValueChangeHandler(new ValueChangeHandler<String>() { | |
@Override | |
public void onValueChange(ValueChangeEvent<String> valueChangeEvent) { | |
moreMenu.hide(); | |
} | |
})); | |
} | |
} | |
item.setEnabled(textButton.isEnabled()); | |
handlerRegistration.add(item.addSelectionHandler(new SelectionHandler<Item>() { | |
@Override | |
public void onSelection(SelectionEvent<Item> event) { | |
textButton.fireEvent(new SelectEvent()); | |
} | |
})); | |
addMenuItemToMoreMenu(w, menu, item); | |
} | |
/** | |
* @since 4.0.3 | |
*/ | |
protected void addWidgetToMenuSplitButton(Menu menu, Widget w) { | |
final SplitButton sb = (SplitButton) w; | |
MenuItem item = new MenuItem(sb.getText(), sb.getIcon()); | |
item.setEnabled(sb.isEnabled()); | |
item.setItemId(sb.getItemId()); | |
if (sb.getData(PROVIDE_MENU_TEXT_DATA_KEY) != null) { | |
item.setHTML(SimpleHtmlSanitizer.sanitizeHtml(sb.getData(PROVIDE_MENU_TEXT_DATA_KEY).toString())); | |
} | |
if (sb.getMenu() != null) { | |
item.setSubMenu(sb.getMenu()); | |
} | |
handlerRegistration.add(item.addSelectionHandler(new SelectionHandler<Item>() { | |
@Override | |
public void onSelection(SelectionEvent<Item> event) { | |
sb.fireEvent(new SelectEvent()); | |
} | |
})); | |
addMenuItemToMoreMenu(w, menu, item); | |
} | |
/** | |
* @since 4.0.3 | |
*/ | |
protected void afterAddWidgetToMenu(Menu menu) { | |
if (menu.getWidgetCount() > 0) { | |
if (menu.getWidget(0) instanceof SeparatorMenuItem) { | |
menu.remove(menu.getWidget(0)); | |
} | |
if (menu.getWidgetCount() > 0) { | |
if (menu.getWidget(menu.getWidgetCount() - 1) instanceof SeparatorMenuItem) { | |
menu.remove(menu.getWidget(menu.getWidgetCount() - 1)); | |
} | |
} | |
} | |
} | |
protected void clearMenu() { | |
moreMenu.clear(); | |
} | |
@Override | |
protected void doLayout() { | |
Size size = getElement().getStyleSize(); | |
if (GXTLogConfiguration.loggingIsEnabled()) { | |
logger.finest(getId() + " doLayout size: " + size); | |
} | |
if ((size.getHeight() == 0 && size.getWidth() == 0) || size.getWidth() == 0) { | |
return; | |
} | |
int w = size.getWidth() - getScrollOffset(); | |
int h = size.getHeight(); | |
int styleHeight = Util.parseInt(getElement().getStyle().getProperty("height"), Style.DEFAULT); | |
int styleWidth = Util.parseInt(getElement().getStyle().getProperty("width"), Style.DEFAULT); | |
boolean findWidth = styleWidth == -1; | |
boolean findHeight = styleHeight == -1; | |
if (GXTLogConfiguration.loggingIsEnabled()) { | |
logger.finest(getId() + " findWidth: " + findWidth + " findHeight: " + findHeight); | |
} | |
int calculateWidth = 0; | |
int maxWidgetHeight = 0; | |
int maxMarginTop = 0; | |
int maxMarginBottom = 0; | |
for (int i = 0, len = getWidgetCount(); i < len; i++) { | |
Widget widget = getWidget(i); | |
BoxLayoutData layoutData = null; | |
Object d = widget.getLayoutData(); | |
if (d instanceof BoxLayoutData) { | |
layoutData = (BoxLayoutData) d; | |
} else { | |
layoutData = new BoxLayoutData(); | |
widget.setLayoutData(layoutData); | |
} | |
Margins cm = layoutData.getMargins(); | |
if (cm == null) { | |
cm = new Margins(0); | |
layoutData.setMargins(cm); | |
} | |
} | |
if (findWidth || findHeight) { | |
for (int i = 0, len = getWidgetCount(); i < len; i++) { | |
Widget widget = getWidget(i); | |
if (!widget.isVisible()) { | |
continue; | |
} | |
BoxLayoutData layoutData = (BoxLayoutData) widget.getLayoutData(); | |
Margins cm = layoutData.getMargins(); | |
calculateWidth += widget.getOffsetWidth(); | |
maxWidgetHeight = Math.max(maxWidgetHeight, widget.getOffsetHeight()); | |
calculateWidth += (cm.getLeft() + cm.getRight()); | |
maxMarginTop = Math.max(maxMarginTop, cm.getTop()); | |
maxMarginBottom = Math.max(maxMarginBottom, cm.getBottom()); | |
} // end for | |
maxWidgetHeight += (maxMarginTop + maxMarginBottom); | |
if (findWidth) { | |
w = calculateWidth; | |
} | |
if (findHeight) { | |
h = maxWidgetHeight; | |
} | |
} // end findWidth/Height | |
int padlLeft = 0; | |
int padTop = 0; | |
int padBottom = 0; | |
int padRight = 0; | |
if (getPadding() != null) { | |
padlLeft = getPadding().getLeft(); | |
padTop = getPadding().getTop(); | |
padBottom = getPadding().getBottom(); | |
padRight = getPadding().getRight(); | |
} | |
if (findHeight) { | |
h += padTop + padBottom; | |
} | |
if (findWidth) { | |
w += padlLeft + padRight; | |
} | |
int stretchHeight = h - padTop - padBottom; | |
int totalFlex = 0; | |
int totalWidth = 0; | |
int maxHeight = 0; | |
for (int i = 0, len = getWidgetCount(); i < len; i++) { | |
Widget widget = getWidget(i); | |
widget.addStyleName(CommonStyles.get().positionable()); | |
widget.getElement().getStyle().setMargin(0, Unit.PX); | |
if (!widget.isVisible()) { | |
continue; | |
} | |
if (widget == more) { | |
triggerWidth = widget.getOffsetWidth() + 10; | |
} | |
BoxLayoutData layoutData = (BoxLayoutData) widget.getLayoutData(); | |
Margins cm = layoutData.getMargins(); | |
// There is an issue where getOffsetWidth call in 2nd loop is returning smaller number than actual offset | |
// when packing CENTER or END so we cache the offsetWidth for use in 2nd loop | |
// with buttons, the button is word wrapping causing the button to be narrower and taller | |
int ww = widget.getOffsetWidth(); | |
loopWidthMap.put(widget, ww); | |
loopHeightMap.put(widget, widget.getOffsetHeight()); | |
totalFlex += layoutData.getFlex(); | |
totalWidth += (ww + cm.getLeft() + cm.getRight()); | |
maxHeight = Math.max(maxHeight, widget.getOffsetHeight() + cm.getTop() + cm.getBottom()); | |
} // end for | |
int innerCtHeight = maxHeight + padTop + padBottom; | |
if (hBoxLayoutAlign.equals(HBoxLayoutAlign.STRETCH)) { | |
getContainerTarget().setSize(w, h, true); | |
} else if (hBoxLayoutAlign.equals(HBoxLayoutAlign.MIDDLE) || hBoxLayoutAlign.equals(HBoxLayoutAlign.BOTTOM)) { | |
getContainerTarget().setSize(w, h = Math.max(h, innerCtHeight), true); | |
} else { | |
getContainerTarget().setSize(w, innerCtHeight, true); | |
} | |
int extraWidth = w - totalWidth - padlLeft - padRight; | |
int allocated = 0; | |
int componentWidth, componentHeight, componentTop; | |
int availableHeight = h - padTop - padBottom; | |
if (getPack().equals(BoxLayoutPack.CENTER)) { | |
padlLeft += extraWidth / 2; | |
} else if (getPack().equals(BoxLayoutPack.END)) { | |
padlLeft += extraWidth; | |
} | |
for (int i = 0, len = getWidgetCount(); i < len; i++) { | |
Widget widget = getWidget(i); | |
if (!widget.isVisible()) { | |
continue; | |
} | |
BoxLayoutData layoutData = (BoxLayoutData) widget.getLayoutData(); | |
Margins cm = layoutData.getMargins(); | |
componentWidth = loopWidthMap.remove(widget); | |
componentHeight = loopHeightMap.remove(widget); | |
padlLeft += cm.getLeft(); | |
padlLeft = Math.max(0, padlLeft); | |
if (hBoxLayoutAlign.equals(HBoxLayoutAlign.MIDDLE)) { | |
int diff = availableHeight - (componentHeight + cm.getTop() + cm.getBottom()); | |
if (diff == 0) { | |
componentTop = padTop + cm.getTop(); | |
} else { | |
componentTop = padTop + cm.getTop() + (diff / 2); | |
} | |
} else { | |
if (hBoxLayoutAlign.equals(HBoxLayoutAlign.BOTTOM)) { | |
componentTop = h - (padBottom + cm.getBottom() + componentHeight); | |
} else { | |
componentTop = padTop + cm.getTop(); | |
} | |
} | |
boolean component = widget instanceof Component; | |
Component c = null; | |
if (component) { | |
c = (Component) widget; | |
} | |
int width = -1; | |
if (component) { | |
c.setPosition(padlLeft, componentTop); | |
} else { | |
XElement.as(widget.getElement()).setLeftTop(padlLeft, componentTop); | |
} | |
if (getPack().equals(BoxLayoutPack.START) && layoutData.getFlex() > 0) { | |
int add = (int) Math.floor(extraWidth * (layoutData.getFlex() / totalFlex)); | |
allocated += add; | |
if (isAdjustForFlexRemainder() && i == getWidgetCount() - 1) { | |
add += (extraWidth - allocated); | |
} | |
componentWidth += add; | |
width = componentWidth; | |
} | |
if (hBoxLayoutAlign.equals(HBoxLayoutAlign.STRETCH)) { | |
applyLayout(widget, width, Util.constrain(stretchHeight - cm.getTop() - cm.getBottom(), layoutData.getMinSize(), | |
layoutData.getMaxSize())); | |
} else if (hBoxLayoutAlign.equals(HBoxLayoutAlign.STRETCHMAX)) { | |
applyLayout(widget, width, | |
Util.constrain(maxHeight - cm.getTop() - cm.getBottom(), layoutData.getMinSize(), layoutData.getMaxSize())); | |
} else if (width > 0) { | |
applyLayout(widget, width, -1); | |
} | |
padlLeft += componentWidth + cm.getRight(); | |
} // end for | |
// do we need overflow | |
if (enableOverflow) { | |
int runningWidth = 0; | |
for (int i = 0, len = getWidgetCount(); i < len; i++) { | |
Widget widget = getWidget(i); | |
if (widget == more) { | |
continue; | |
} | |
BoxLayoutData layoutData = null; | |
Object d = widget.getLayoutData(); | |
if (d instanceof BoxLayoutData) { | |
layoutData = (BoxLayoutData) d; | |
} else { | |
layoutData = new BoxLayoutData(); | |
} | |
Margins cm = layoutData.getMargins(); | |
if (cm == null) { | |
cm = new Margins(0); | |
} | |
runningWidth += getWidgetWidth(widget); | |
runningWidth += cm.getLeft(); | |
runningWidth += cm.getRight(); | |
} | |
if (runningWidth > w) { | |
hasOverflow = true; | |
onOverflow(); | |
} else { | |
hasOverflow = false; | |
onUnoverflow(); | |
} | |
} | |
} | |
protected int getWidgetWidth(Widget widget) { | |
Integer w = widthMap.get(widget); | |
if (w != null) { | |
return w; | |
} else { | |
return widget.getOffsetWidth(); | |
} | |
} | |
protected void hideComponent(Widget w) { | |
widthMap.put(w, w.getOffsetWidth()); | |
hiddens.add(w); | |
w.setVisible(false); | |
} | |
protected void initMore() { | |
if (more == null) { | |
moreMenu = new Menu(); | |
moreMenu.setEnableScrolling(isMoreMenuEnableScrolling()); | |
moreMenu.addBeforeShowHandler(new BeforeShowHandler() { | |
@Override | |
public void onBeforeShow(BeforeShowEvent event) { | |
HBoxLayoutContainer.this.onBeforeShow(event); | |
} | |
}); | |
more = new TextButton(); | |
more.addStyleName("x-toolbar-more"); | |
more.addStyleName(getAppearance().moreButtonStyle()); | |
more.setData("x-ignore-width", true); | |
more.setData("gxt-more", "true"); | |
more.setIcon(getAppearance().moreIcon()); | |
more.setMenu(moreMenu); | |
} | |
if (more.getParent() != this) { | |
add(more); | |
} | |
} | |
/** | |
* Called before showing more menu. | |
* <p> | |
* | |
* @param event the before show event | |
* @since 4.0.3 | |
*/ | |
protected void onBeforeShow(BeforeShowEvent event) { | |
handlerRegistration.removeHandler(); | |
clearMenu(); | |
int widgetCount = getWidgetCount(); | |
for (int i = 0; i < widgetCount; i++) { | |
Widget w = getWidget(i); | |
if (isHidden(w) && w != more) { | |
if (moreMenuItems != null && moreMenuItems.get(i) != null) { | |
addWidgetToMenuFromMoreMenuItemsMap(moreMenu, w, i); | |
} else { | |
addWidgetToMenu(moreMenu, w); | |
} | |
} | |
} | |
fireEvent(new OverflowEvent(moreMenu)); | |
} | |
/** | |
* Add a menu from the more menu items map. Menu item will not hide on click by default. | |
* <p> | |
* | |
* @param moreMenu the more items menu | |
* @param widget the widget that doesn't fit | |
* @param index the widget index | |
* @since 4.0.3 | |
*/ | |
protected void addWidgetToMenuFromMoreMenuItemsMap(Menu moreMenu, Widget widget, int index) { | |
MenuItem menuItem = moreMenuItems.get(index); | |
menuItem.setHideOnClick(false); | |
moreMenu.add(menuItem); | |
} | |
protected boolean isHidden(Widget w) { | |
return hiddens != null && hiddens.contains(w); | |
} | |
@Override | |
protected void onInsert(int index, Widget child) { | |
super.onInsert(index, child); | |
child.addStyleName(CommonStyles.get().floatLeft()); | |
} | |
@Override | |
protected void onRemove(Widget child) { | |
super.onRemove(child); | |
child.removeStyleName(CommonStyles.get().floatLeft()); | |
} | |
protected void onOverflow() { | |
Size size = getElement().getStyleSize(); | |
final int w = size.getWidth() - getScrollOffset() - triggerWidth; | |
boolean change = false; | |
int loopWidth = 0; | |
for (int i = 0; i < getWidgetCount(); i++) { | |
Widget widget = getWidget(i); | |
if (widget == more) | |
continue; | |
if (!(widget instanceof FillToolItem)) { | |
loopWidth += getWidgetWidth(widget); | |
BoxLayoutData data = (BoxLayoutData) widget.getLayoutData(); | |
if (data != null && data.getMargins() != null) { | |
loopWidth += (data.getMargins().getLeft() + data.getMargins().getRight()); | |
} | |
if (loopWidth >= w) { | |
if (!isHidden(widget)) { | |
change = true; | |
hideComponent(widget); | |
} | |
} else { | |
if (isHidden(widget)) { | |
change = true; | |
unhideComponent(widget); | |
} | |
} | |
} | |
} | |
if (hiddens != null && hiddens.size() > 0) { | |
initMore(); | |
} | |
if (change) { | |
Scheduler.get().scheduleDeferred(new ScheduledCommand() { | |
@Override | |
public void execute() { | |
forceLayout(); | |
} | |
}); | |
} | |
} | |
protected void onUnoverflow() { | |
boolean change = false; | |
for (int i = 0; i < getWidgetCount(); i++) { | |
Widget widget = getWidget(i); | |
if (widget == more) | |
continue; | |
if (isHidden(widget)) { | |
change = true; | |
unhideComponent(widget); | |
} | |
} | |
if (more != null && more.getParent() == HBoxLayoutContainer.this) { | |
change = true; | |
remove(more); | |
} | |
if (change) { | |
Scheduler.get().scheduleDeferred(new ScheduledCommand() { | |
@Override | |
public void execute() { | |
forceLayout(); | |
} | |
}); | |
} | |
} | |
protected void unhideComponent(Widget w) { | |
if (hiddens.remove(w)) { | |
widthMap.remove(w); | |
w.setVisible(true); | |
} | |
} | |
/** | |
* Returns if the more menu has enabled scrolling. | |
* | |
* @return true or false | |
* @since 4.0.3 | |
*/ | |
public boolean isMoreMenuEnableScrolling() { | |
return moreMenuEnableScrolling; | |
} | |
/** | |
* Enable more menu scrolling. | |
* | |
* @param moreMenuEnableScrolling turn on enabled scrolling for more menu | |
* @since 4.0.3 | |
*/ | |
public void setMoreMenuEnableScrolling(boolean moreMenuEnableScrolling) { | |
this.moreMenuEnableScrolling = moreMenuEnableScrolling; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.sencha.gxt.test.client.layout_hboxlayoutcontainer; | |
import com.google.gwt.core.client.EntryPoint; | |
import com.google.gwt.core.client.GWT; | |
import com.google.gwt.uibinder.client.UiBinder; | |
import com.google.gwt.user.client.ui.RootPanel; | |
import com.google.gwt.user.client.ui.Widget; | |
import com.sencha.gxt.test.client.TestSample; | |
@TestSample( | |
name = "HBoxLayout with UiBinder", | |
description = { "Expectation, no rendering exceptions.", "Verify you can see two buttons.", | |
"No need to test more than browser." }, | |
jiraIds = { 4735 }) | |
public class HBoxWithUiBinderTestCase implements EntryPoint { | |
interface MyUiBinder extends UiBinder<Widget, HBoxWithUiBinderTestCase> { | |
} | |
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); | |
@Override | |
public void onModuleLoad() { | |
Widget widget = uiBinder.createAndBindUi(this); | |
widget.setPixelSize(400, 400); | |
RootPanel.get().add(widget); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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" | |
xmlns:container="urn:import:com.sencha.gxt.widget.core.client.container" | |
xmlns:button="urn:import:com.sencha.gxt.widget.core.client.button" | |
xmlns:gxt="urn:import:com.sencha.gxt.widget.core.client" | |
xmlns:tb="urn:import:com.sencha.gxt.widget.core.client.button"> | |
<gxt:ContentPanel heading="Horizontal Box Layout" pixelSize="600, 500"> | |
<container:HBoxLayoutContainer> | |
<container:child> | |
<button:TextButton text="Button Item 1"></button:TextButton> | |
</container:child> | |
<container:sibling> | |
<button:TextButton text="Button Item 2"></button:TextButton> | |
</container:sibling> | |
</container:HBoxLayoutContainer> | |
</gxt:ContentPanel> | |
</ui:UiBinder> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This will be fixed in the 4.0.4 nightly.