StackLayoutPanel class
A panel that stacks its children vertically, displaying only one at a time, with a header for each child which the user can click to display.
This widget will only work in standards mode, which requires that the HTML page in which it is run have an explicit <!DOCTYPE> declaration.
CSS Style Rules
- .gwt-StackLayoutPanel
- the panel itself
- .gwt-StackLayoutPanel .gwt-StackLayoutPanelHeader
- applied to each header widget
- .gwt-StackLayoutPanel .gwt-StackLayoutPanelHeader-hovering
- applied to each header widget on mouse hover
- .gwt-StackLayoutPanel .gwt-StackLayoutPanelContent
- applied to each child widget
Example
{@example com.google.gwt.examples.StackLayoutPanelExample}Use in UiBinder Templates
A StackLayoutPanel element in a
{@link com.google.gwt.uibinder.client.UiBinder UiBinder} template may have a
unit
attribute with a
{@link com.google.gwt.dom.client.Style.Unit Style.Unit} value (it defaults to
PX).
The children of a StackLayoutPanel element are laid out in <g:stack>
elements. Each stack can have one widget child and one of two types of header
elements. A <g:header> element can hold html, or a <g:customHeader>
element can hold a widget. (Note that the tags of the header elements are not
capitalized. This is meant to signal that the head is not a runtime object,
and so cannot have a ui:field
attribute.)
For example:
<g:StackLayoutPanel unit='PX'> <g:stack> <g:header size='3'><b>HTML</b> header</g:header> <g:Label>able</g:Label> </g:stack> <g:stack> <g:customHeader size='3'> <g:Label>Custom header</g:Label> </g:customHeader> <g:Label>baker</g:Label> </g:stack> </g:StackLayoutPanel>
class StackLayoutPanel extends ResizeComposite implements HasWidgets, ProvidesResize, IndexedPanelForIsWidget, AnimatedLayout, HasBeforeSelectionHandlers<int>, HasSelectionHandlers<int> { static final String _WIDGET_STYLE = "dwt-StackLayoutPanel"; static final String _CONTENT_STYLE = "dwt-StackLayoutPanelContent"; static final String _HEADER_STYLE = "dwt-StackLayoutPanelHeader"; static final String _HEADER_STYLE_HOVERING = "dwt-StackLayoutPanelHeader-hovering"; static final int _ANIMATION_TIME = 250; int _animationDuration = _ANIMATION_TIME; LayoutPanel layoutPanel; final Unit _unit; final List<_LayoutData> _layoutData = new List<_LayoutData>(); int _selectedIndex = -1; /** * Creates an empty stack panel. * * @param unit the unit to be used for layout */ StackLayoutPanel(this._unit) : layoutPanel = new LayoutPanel() { initWidget(layoutPanel); clearAndSetStyleName(_WIDGET_STYLE); } void add(Widget w) { assert (false); // : "Single-argument add() is not supported for this widget"; } /** * Adds a child widget to this stack, along with a widget representing the * stack header. * * @param widget the child widget to be added * @param header the text to be shown on its header * @param asHtml <code>true</code> to treat the specified text as HTML * @param headerSize the size of the header widget */ void addWidget(Widget widget, String header, bool asHtml, double headerSize) { insertAsText(widget, header, asHtml, headerSize, getWidgetCount()); } /** * Overloaded version for IsWidget. * * @see #add(Widget,String,boolean,double) */ void addIsWidget(IsWidget widget, String header, bool asHtml, double headerSize) { this.addWidget(widget.asWidget(), header, asHtml, headerSize); } HandlerRegistration addBeforeSelectionHandler(BeforeSelectionHandler<int> handler) { return addHandler(handler, BeforeSelectionEvent.TYPE); } HandlerRegistration addSelectionHandler(SelectionHandler<int> handler) { return addHandler(handler, SelectionEvent.TYPE); } void animate(int duration, [LayoutAnimationCallback callback = null]) { // Don't try to animate zero widgets. if (_layoutData.length == 0) { if (callback != null) { callback.onAnimationComplete(); } return; } double top = 0.0, bottom = 0.0; int i = 0; for (; i < _layoutData.length; ++i) { _LayoutData data = _layoutData[i]; layoutPanel.setWidgetTopHeight(data.header, top, _unit, data.headerSize, _unit); top += data.headerSize; layoutPanel.setWidgetTopHeight(data.widget, top, _unit, 0.0, _unit); if (i == _selectedIndex) { break; } } for (int j = _layoutData.length - 1; j > i; --j) { _LayoutData data = _layoutData[j]; layoutPanel.setWidgetBottomHeight(data.header, bottom, _unit, data.headerSize, _unit); layoutPanel.setWidgetBottomHeight(data.widget, bottom, _unit, 0.0, _unit); bottom += data.headerSize; } _LayoutData data = _layoutData[_selectedIndex]; layoutPanel.setWidgetTopBottom(data.widget, top, _unit, bottom, _unit); layoutPanel.animate(duration, callback); } void clear() { layoutPanel.clear(); _layoutData.clear(); _selectedIndex = -1; } void forceLayout() { layoutPanel.forceLayout(); } /** * Get the duration of the animated transition between children. * * @return the duration in milliseconds */ int getAnimationDuration() { return _animationDuration; } /** * Gets the widget in the stack header at the given index. * * @param index the index of the stack header to be retrieved * @return the header widget */ Widget getHeaderWidgetAt(int index) { checkIndex(index); return _layoutData[index].header.getWidget(); } /** * Gets the widget in the stack header associated with the given child widget. * * @param child the child whose stack header is to be retrieved * @return the header widget */ Widget getHeaderWidget(Widget child) { checkChild(child); return getHeaderWidgetAt(getWidgetIndex(child)); } /** * Gets the currently-selected index. * * @return the selected index, or <code>-1</code> if none is selected */ int getVisibleIndex() { return _selectedIndex; } /** * Gets the currently-selected widget. * * @return the selected widget, or <code>null</code> if none exist */ Widget getVisibleWidget() { if (_selectedIndex == -1) { return null; } return getWidgetAt(_selectedIndex); } Widget getWidgetAt(int index) { return layoutPanel.getWidgetAt(index * 2 + 1); } int getWidgetCount() { return layoutPanel.getWidgetCount() ~/ 2; } int getWidgetIndexIsWidget(IsWidget child) { return getWidgetIndex(Widget.asWidgetOrNull(child)); } int getWidgetIndex(Widget child) { int index = layoutPanel.getWidgetIndex(child); if (index == -1) { return index; } return (index - 1) ~/ 2; } /** * Inserts a widget into the panel. If the Widget is already attached, it will * be moved to the requested index. * * @param child the widget to be added * @param text the text to be shown on its header * @param asHtml <code>true</code> to treat the specified text as HTML * @param headerSize the size of the header widget * @param beforeIndex the index before which it will be inserted */ void insertAsText(Widget child, String text, bool asHtml, double headerSize, int beforeIndex) { Html contents = new Html(); if (asHtml) { contents.html = text; } else { contents.text = text; } insert(child, new _Header(contents), headerSize, beforeIndex); } Iterator<Widget> iterator() { return new _Iterator(this); } void onResize() { layoutPanel.onResize(); } bool removeAt(int index) { return remove(getWidgetAt(index)); } bool remove(Widget child) { if (child.getParent() != layoutPanel) { return false; } // Find the layoutData associated with this widget and remove it. for (int i = 0; i < _layoutData.length; ++i) { _LayoutData data = _layoutData[i]; if (data.widget == child) { layoutPanel.remove(data.header); layoutPanel.remove(data.widget); data.header.removeStyleName(_HEADER_STYLE); data.widget.removeStyleName(_CONTENT_STYLE); _layoutData.removeAt(i); if (_selectedIndex == i) { _selectedIndex = -1; if (_layoutData.length > 0) { showWidgetAt(getWidgetIndex(_layoutData[0].widget)); } } else { if (i <= _selectedIndex) { _selectedIndex--; } animate(_animationDuration); } return true; } } return false; } /** * Set the duration of the animated transition between children. * * @param duration the duration in milliseconds. */ void setAnimationDuration(int duration) { this._animationDuration = duration; } /** * Sets a stack header's HTML contents. * * Use care when setting an object's HTML; it is an easy way to expose * script-based security problems. Consider using * {@link #setHeaderHTML(int, SafeHtml)} or * {@link #setHeaderText(int, String)} whenever possible. * * @param index the index of the header whose HTML is to be set * @param html the header's new HTML contents */ void setHeaderHtml(int index, String html) { checkIndex(index); _LayoutData data = _layoutData[index]; Widget headerWidget = data.header.getWidget(); assert (headerWidget is HasHtml); // : "Header widget does not implement HasHTML"; (headerWidget as HasHtml).html = html; } /** * Sets a stack header's text contents. * * @param index the index of the header whose text is to be set * @param text the object's new text */ void setHeaderText(int index, String text) { checkIndex(index); _LayoutData data = _layoutData[index]; Widget headerWidget = data.header.getWidget(); assert (headerWidget is HasText); // : "Header widget does not implement HasText"; (headerWidget as HasText).text = text; } /** * Shows the specified widget. * * @param child the child widget to be shown. * @param fireEvents true to fire events, false not to */ void showWidget(Widget child, [bool fireEvents = false]) { showWidgetAt(getWidgetIndex(child), _animationDuration, fireEvents); } void onLoad() { // When the widget becomes attached, update its layout. animate(0); } void checkChild(Widget child) { assert (layoutPanel.getChildren().contains(child)); } void checkIndex(int index) { assert ((index >= 0) && (index < getWidgetCount())); // : "Index out of bounds"; } void insert(Widget child, _Header header, double headerSize, int beforeIndex) { assert ((beforeIndex >= 0) && (beforeIndex <= getWidgetCount())); // : "beforeIndex out of bounds"; // Check to see if the StackPanel already contains the Widget. If so, // remove it and see if we need to shift the position to the left. int idx = getWidgetIndex(child); if (idx != -1) { remove(child); if (idx < beforeIndex) { beforeIndex--; } } int widgetIndex = beforeIndex * 2; layoutPanel.insertAt(child, widgetIndex); layoutPanel.insertAt(header, widgetIndex); layoutPanel.setWidgetLeftRight(header, 0.0, Unit.PX, 0.0, Unit.PX); layoutPanel.setWidgetLeftRight(child, 0.0, Unit.PX, 0.0, Unit.PX); _LayoutData data = new _LayoutData(child, header, headerSize); if (beforeIndex < _layoutData.length) { // _layoutData.insertRange(beforeIndex, 1); // _layoutData[beforeIndex] = data; _layoutData.insert(beforeIndex, data); } else { _layoutData.add(data); } header.addStyleName(_HEADER_STYLE); child.addStyleName(_CONTENT_STYLE); header.addClickHandler(new ClickHandlerAdapter((ClickEvent event) { showWidget(child); })); header.addMouseOutHandler(new MouseOutHandlerAdapter((MouseOutEvent event) { header.removeStyleName(_HEADER_STYLE_HOVERING); })); header.addMouseOverHandler(new MouseOverHandlerAdapter((MouseOverEvent event) { header.addStyleName(_HEADER_STYLE_HOVERING); })); if (_selectedIndex == -1) { // If there's no visible widget, display the first one. The layout will // be updated onLoad(). showWidgetAt(0); } else if (beforeIndex <= _selectedIndex) { // If we inserted an item before the selected index, increment it. _selectedIndex++; } // If the widget is already attached, we must call animate() to update the // layout (if it's not yet attached, then onLoad() will do this). if (isAttached()) { animate(_animationDuration); } } void showWidgetAt(int index, [int duration = null, bool fireEvents = false]) { checkIndex(index); if (index == _selectedIndex) { return; } // Fire the before selection event, giving the recipients a chance to // cancel the selection. if (fireEvents) { BeforeSelectionEvent<int> event = BeforeSelectionEvent.fire(this, index); if ((event != null) && event.isCanceled()) { return; } } _selectedIndex = index; if (isAttached()) { animate(duration == null ? _animationDuration : duration); } // Fire the selection event. if (fireEvents) { SelectionEvent.fire(this, index); } } }
Extends
UiObject > Widget > Composite > ResizeComposite > StackLayoutPanel
Implements
HasSelectionHandlers<int>, HasBeforeSelectionHandlers<int>, AnimatedLayout, IndexedPanelForIsWidget, ProvidesResize, HasWidgets
Constructors
Properties
int eventsToSink #
A set og events that should be sunk when the widget is attached to the DOM. (We delay the sinking of events to improve startup performance.) When the widget is attached, this is set is empty
Package protected to allow Composite to see it.
int eventsToSink = 0
LayoutPanel layoutPanel #
LayoutPanel layoutPanel
String get title #
Gets the title associated with this object. The title is the 'tool-tip' displayed to users when they hover over the object.
@return the object's title
String get title => getElement().title;
void set title(String value) #
Sets the element's title.
void set title(String value) { getElement().title = value; }
bool get visible #
Determines whether or not this object is visible. Note that this does not necessarily take into account whether or not the receiver's parent is visible, or even if it is attached to the Document. The default implementation of this trait in UIObject is based on the value of a dom element's style object's display attribute.
@return <code>true</code> if the object is visible
bool get visible => isVisible(getElement());
Methods
void add(Widget w) #
Adds a child widget.
@param w the widget to be added @throws UnsupportedOperationException if this method is not supported (most
often this means that a specific overload must be called)
void add(Widget w) { assert (false); // : "Single-argument add() is not supported for this widget"; }
HandlerRegistration addAttachHandler(AttachEventHandler handler) #
Adds an AttachEvent handler.
@param handler the handler @return the handler registration
HandlerRegistration addAttachHandler(AttachEventHandler handler) { return addHandler(handler, AttachEvent.TYPE); }
HandlerRegistration addBeforeSelectionHandler(BeforeSelectionHandler<int> handler) #
Adds a {@link BeforeSelectionEvent} handler.
@param handler the handler @return the registration for the event
HandlerRegistration addBeforeSelectionHandler(BeforeSelectionHandler<int> handler) { return addHandler(handler, BeforeSelectionEvent.TYPE); }
HandlerRegistration addBitlessDomHandler(EventHandler handler, DomEventType type) #
For <a href= "http://code.google.com/p/google-web-toolkit/wiki/UnderstandingMemoryLeaks"
browsers which do not leak</a>, adds a native event handler to the widget.
Note that, unlike the {@link #addDomHandler(EventHandler, com.google.gwt.event.dom.client.DomEvent.Type)} implementation, there is no need to attach the widget to the DOM in order to cause the event handlers to be attached.
@param <H> the type of handler to add @param type the event key @param handler the handler @return {@link HandlerRegistration} used to remove the handler
HandlerRegistration addBitlessDomHandler(EventHandler handler, DomEventType type) { assert (handler != null);; // : "handler must not be null"; assert (type != null); // : "type must not be null"; sinkBitlessEvent(type.eventName); return ensureHandlers().addHandler(type, handler); }
HandlerRegistration addDomHandler(EventHandler handler, DomEventType type) #
Adds a native event handler to the widget and sinks the corresponding native event. If you do not want to sink the native event, use the generic addHandler method instead.
@param <H> the type of handler to add @param type the event key @param handler the handler @return {@link HandlerRegistration} used to remove the handler
HandlerRegistration addDomHandler(EventHandler handler, DomEventType type) { assert (handler != null); // : "handler must not be null"; assert (type != null); // : "type must not be null"; int typeInt = IEvent.getTypeInt(type.eventName); if (typeInt == -1) { sinkBitlessEvent(type.eventName); } else { sinkEvents(typeInt); } return ensureHandlers().addHandler(type, handler); }
HandlerRegistration addHandler(EventHandler handler, EventType<EventHandler> type) #
Adds this handler to the widget.
@param <H> the type of handler to add @param type the event type @param handler the handler @return {@link HandlerRegistration} used to remove the handler
HandlerRegistration addHandler(EventHandler handler, EventType<EventHandler> type) { return ensureHandlers().addHandler(type, handler); }
void addIsWidget(IsWidget widget, String header, bool asHtml, double headerSize) #
Overloaded version for IsWidget.
@see #add(Widget,String,boolean,double)
void addIsWidget(IsWidget widget, String header, bool asHtml, double headerSize) { this.addWidget(widget.asWidget(), header, asHtml, headerSize); }
HandlerRegistration addSelectionHandler(SelectionHandler<int> handler) #
Adds a {@link SelectionEvent} handler.
@param handler the handler @return the registration for the event
HandlerRegistration addSelectionHandler(SelectionHandler<int> handler) { return addHandler(handler, SelectionEvent.TYPE); }
void addStyleDependentName(String styleSuffix) #
Adds a dependent style name by specifying the style name's suffix. The actual form of the style name that is added is:
getStylePrimaryName() + '-' + styleSuffix
@param styleSuffix the suffix of the dependent style to be added. @see #setStylePrimaryName(String) @see #removeStyleDependentName(String) @see #setStyleDependentName(String, boolean) @see #addStyleName(String)
void addStyleDependentName(String styleSuffix) { setStyleDependentName(styleSuffix, true); }
void addStyleName(String style) #
Adds a secondary or dependent style name to this object. A secondary style name is an additional style name that is, in HTML/CSS terms, included as a space-separated token in the value of the CSS <code>class</code> attribute for this object's root element.
The most important use for this method is to add a special kind of
secondary style name called a dependent style name. To add a
dependent style name, use {@link #addStyleDependentName(String)}, which
will prefix the 'style' argument with the result of
{@link #k()} (followed by a '-'). For example, suppose
the primary style name is gwt-TextBox
. If the following method
is called as obj.setReadOnly(true)
:
public void setReadOnly(boolean readOnly) { isReadOnlyMode = readOnly;// Create a dependent style name. String readOnlyStyle = "readonly";
if (readOnly) {
addStyleDependentName(readOnlyStyle);
} else {
removeStyleDependentName(readOnlyStyle);
} }</pre>
then both of the CSS style rules below will be applied:
// This rule is based on the primary style name and is always active. .gwt-TextBox { font-size: 12pt; }
// This rule is based on a dependent style name that is only active // when the widget has called addStyleName(getStylePrimaryName() + // "-readonly"). .gwt-TextBox-readonly { background-color: lightgrey; border: none; }</pre>
The code can also be simplified with {@link #setStyleDependentName(String, boolean)}:
public void setReadOnly(boolean readOnly) { isReadOnlyMode = readOnly; setStyleDependentName("readonly", readOnly); }Dependent style names are powerful because they are automatically updated whenever the primary style name changes. Continuing with the example above, if the primary style name changed due to the following call:
setStylePrimaryName("my-TextThingy");then the object would be re-associated with following style rules, removing those that were shown above.
.my-TextThingy { font-size: 20pt; }.my-TextThingy-readonly { background-color: red; border: 2px solid yellow; }</pre>
Secondary style names that are not dependent style names are not automatically updated when the primary style name changes.
@param style the secondary style name to be added @see UIObject @see #removeStyleName(String)
void addStyleName(String style) { setStyleName(style, true); }
void addWidget(Widget widget, String header, bool asHtml, double headerSize) #
Adds a child widget to this stack, along with a widget representing the stack header.
@param widget the child widget to be added @param header the text to be shown on its header @param asHtml <code>true</code> to treat the specified text as HTML @param headerSize the size of the header widget
void addWidget(Widget widget, String header, bool asHtml, double headerSize) { insertAsText(widget, header, asHtml, headerSize, getWidgetCount()); }
void animate(int duration, [LayoutAnimationCallback callback = null]) #
Layout children, animating over the specified period of time.
This method provides a callback that will be informed of animation updates. This can be used to create more complex animation effects.
@param duration the animation duration, in milliseconds @param callback the animation callback
void animate(int duration, [LayoutAnimationCallback callback = null]) { // Don't try to animate zero widgets. if (_layoutData.length == 0) { if (callback != null) { callback.onAnimationComplete(); } return; } double top = 0.0, bottom = 0.0; int i = 0; for (; i < _layoutData.length; ++i) { _LayoutData data = _layoutData[i]; layoutPanel.setWidgetTopHeight(data.header, top, _unit, data.headerSize, _unit); top += data.headerSize; layoutPanel.setWidgetTopHeight(data.widget, top, _unit, 0.0, _unit); if (i == _selectedIndex) { break; } } for (int j = _layoutData.length - 1; j > i; --j) { _LayoutData data = _layoutData[j]; layoutPanel.setWidgetBottomHeight(data.header, bottom, _unit, data.headerSize, _unit); layoutPanel.setWidgetBottomHeight(data.widget, bottom, _unit, 0.0, _unit); bottom += data.headerSize; } _LayoutData data = _layoutData[_selectedIndex]; layoutPanel.setWidgetTopBottom(data.widget, top, _unit, bottom, _unit); layoutPanel.animate(duration, callback); }
Widget asWidget() #
Returns the Widget aspect of the receiver.
Widget asWidget() { return this; }
void checkChild(Widget child) #
void checkChild(Widget child) { assert (layoutPanel.getChildren().contains(child)); }
void checkIndex(int index) #
void checkIndex(int index) { assert ((index >= 0) && (index < getWidgetCount())); // : "Index out of bounds"; }
void clear() #
Removes all child widgets.
void clear() { layoutPanel.clear(); _layoutData.clear(); _selectedIndex = -1; }
void clearAndSetStyleName(String style) #
Clears all of the object's style names and sets it to the given style. You should normally use {@link #setStylePrimaryName(String)} unless you wish to explicitly remove all existing styles.
@param style the new style name @see #setStylePrimaryName(String)
void clearAndSetStyleName(String style) { setElementStyleName(getStyleElement(), style); }
EventBus createEventBus() #
Creates the SimpleEventBus used by this Widget. You can override this method to create a custom EventBus.
@return the EventBus you want to use.
EventBus createEventBus() { return new SimpleEventBus(); }
void delegateEvent(Widget target, DwtEvent event) #
Fires an event on a child widget. Used to delegate the handling of an event from one widget to another.
@param event the event @param target fire the event on the given target
void delegateEvent(Widget target, DwtEvent event) { target.fireEvent(event); }
void doAttachChildren() #
If a widget contains one or more child widgets that are not in the logical widget hierarchy (the child is physically connected only on the DOM level), it must override this method and call {@link #onAttach()} for each of its child widgets.
@see #onAttach()
void doAttachChildren() { }
void doDetachChildren() #
If a widget contains one or more child widgets that are not in the logical widget hierarchy (the child is physically connected only on the DOM level), it must override this method and call {@link #onDetach()} for each of its child widgets.
@see #onDetach()
void doDetachChildren() { }
EventBus ensureHandlers() #
Ensures the existence of the event bus.
@return the EventBus.
EventBus ensureHandlers() { return _eventBus == null ? _eventBus = createEventBus() : _eventBus; }
double extractLengthValue(String s) #
Intended to be used to pull the value out of a CSS length. If the value is "auto" or "inherit", 0 will be returned.
@param s The CSS length string to extract @return The leading numeric portion of <code>s</code>, or 0 if "auto" or
"inherit" are passed in.
double extractLengthValue(String s) { if (s == "auto" || s == "inherit" || s == "") { return 0.0; } else { // numberRegex divides the string into a leading numeric portion // followed by an arbitrary portion. if(numberRegex.hasMatch(s)) { // Extract the leading numeric portion of string s = numberRegex.firstMatch(s)[0]; } return double.parse(s); } }
void fireEvent(DwtEvent event) #
Fires the given event to the handlers listening to the event's type.
Any exceptions thrown by handlers will be bundled into a UmbrellaException and then re-thrown after all handlers have completed. An exception thrown by a handler will not prevent other handlers from executing.
@param event the event
void fireEvent(DwtEvent event) { // if (_eventBus != null) { // _eventBus.fireEvent(event); // } if (_eventBus != null) { // If it not live we should revive it. if (!event.isLive()) { event.revive(); } Object oldSource = event.getSource(); event.overrideSource(getElement()); try { // May throw an UmbrellaException. _eventBus.fireEventFromSource(event, getElement()); } on UmbrellaException catch (e) { throw new UmbrellaException(e.causes); } finally { if (oldSource == null) { // This was my event, so I should kill it now that I'm done. event.kill(); } else { // Restoring the source for the next handler to use. event.overrideSource(oldSource); } } } }
void forceLayout() #
Layout children immediately.
This is not normally necessary, unless you want to update child widgets' positions explicitly to create a starting point for a subsequent call to {@link #animate(int)}.
@see #animate(int) @see #animate(int, Layout.AnimationCallback)
void forceLayout() { layoutPanel.forceLayout(); }
int getAbsoluteLeft() #
Gets the object's absolute left position in pixels, as measured from the browser window's client area.
@return the object's absolute left position
int getAbsoluteLeft() { return Dom.getAbsoluteLeft(getElement()); }
int getAbsoluteTop() #
Gets the object's absolute top position in pixels, as measured from the browser window's client area.
@return the object's absolute top position
int getAbsoluteTop() { return Dom.getAbsoluteTop(getElement()); }
int getAnimationDuration() #
Get the duration of the animated transition between children.
@return the duration in milliseconds
int getAnimationDuration() { return _animationDuration; }
Element getElement() #
Gets this object's browser element.
dart_html.Element getElement() { assert (_element != null); // : MISSING_ELEMENT_ERROR; return _element; }
EventBus getEventBus() #
Return EventBus.
EventBus getEventBus() { return _eventBus; }
Widget getHeaderWidget(Widget child) #
Gets the widget in the stack header associated with the given child widget.
@param child the child whose stack header is to be retrieved @return the header widget
Widget getHeaderWidget(Widget child) { checkChild(child); return getHeaderWidgetAt(getWidgetIndex(child)); }
Widget getHeaderWidgetAt(int index) #
Gets the widget in the stack header at the given index.
@param index the index of the stack header to be retrieved @return the header widget
Widget getHeaderWidgetAt(int index) { checkIndex(index); return _layoutData[index].header.getWidget(); }
Object getLayoutData() #
Gets the panel-defined layout data associated with this widget.
@return the widget's layout data @see #setLayoutData
Object getLayoutData() { return _layoutData; }
int getOffsetHeight() #
Gets the object's offset height in pixels. This is the total height of the object, including decorations such as border and padding, but not margin.
@return the object's offset height
int getOffsetHeight() { return getElement().offset.height; // Dom.getElementPropertyInt(getElement(), "offsetHeight"); }
int getOffsetWidth() #
Gets the object's offset width in pixels. This is the total width of the object, including decorations such as border and padding, but not margin.
@return the object's offset width
int getOffsetWidth() { return getElement().offset.width; // Dom.getElementPropertyInt(getElement(), "offsetWidth"); }
Widget getParent() #
Gets this widget's parent panel.
@return the widget's parent panel
Widget getParent() { return _parent; }
Element getStyleElement() #
Template method that returns the element to which style names will be applied. By default it returns the root element, but this method may be overridden to apply styles to a child element.
@return the element to which style names will be applied
dart_html.Element getStyleElement() { return getElement(); }
String getStyleName() #
Gets all of the object's style names, as a space-separated list. If you wish to retrieve only the primary style name, call {@link #getStylePrimaryName()}.
@return the objects's space-separated style names @see #getStylePrimaryName()
String getStyleName() { return getElementStyleName(getStyleElement()); }
String getStylePrimaryName() #
Gets the primary style name associated with the object.
@return the object's primary style name @see #setStyleName(String) @see #addStyleName(String) @see #removeStyleName(String)
String getStylePrimaryName() { return getElementStylePrimaryName(getStyleElement()); }
int getVisibleIndex() #
Gets the currently-selected index.
@return the selected index, or <code>-1</code> if none is selected
int getVisibleIndex() { return _selectedIndex; }
Widget getVisibleWidget() #
Gets the currently-selected widget.
@return the selected widget, or <code>null</code> if none exist
Widget getVisibleWidget() { if (_selectedIndex == -1) { return null; } return getWidgetAt(_selectedIndex); }
Widget getWidget() #
Provides subclasses access to the topmost widget that defines this composite.
@return the widget
Widget getWidget() { return _widget; }
Widget getWidgetAt(int index) #
Gets the child widget at the specified index.
@param index the child widget's index @return the child widget
Widget getWidgetAt(int index) { return layoutPanel.getWidgetAt(index * 2 + 1); }
int getWidgetCount() #
Gets the number of child widgets in this panel.
@return the number of children
int getWidgetCount() { return layoutPanel.getWidgetCount() ~/ 2; }
int getWidgetIndex(Widget child) #
Gets the index of the specified child widget.
@param child the widget to be found @return the widget's index, or <code>-1</code> if it is not a child of this
panel
int getWidgetIndex(Widget child) { int index = layoutPanel.getWidgetIndex(child); if (index == -1) { return index; } return (index - 1) ~/ 2; }
int getWidgetIndexIsWidget(IsWidget child) #
int getWidgetIndexIsWidget(IsWidget child) { return getWidgetIndex(Widget.asWidgetOrNull(child)); }
void initWidget(Widget widget) #
Sets the widget to be wrapped by the composite. The wrapped widget must be set before calling any {@link Widget} methods on this object, or adding it to a panel. This method may only be called once for a given composite.
@param widget the widget to be wrapped
void initWidget(Widget widget) { assert (widget is RequiresResize); // : "LayoutComposite requires that its wrapped widget implement RequiresResize"; super.initWidget(widget); }
void insert(Widget child, _Header header, double headerSize, int beforeIndex) #
void insert(Widget child, _Header header, double headerSize, int beforeIndex) { assert ((beforeIndex >= 0) && (beforeIndex <= getWidgetCount())); // : "beforeIndex out of bounds"; // Check to see if the StackPanel already contains the Widget. If so, // remove it and see if we need to shift the position to the left. int idx = getWidgetIndex(child); if (idx != -1) { remove(child); if (idx < beforeIndex) { beforeIndex--; } } int widgetIndex = beforeIndex * 2; layoutPanel.insertAt(child, widgetIndex); layoutPanel.insertAt(header, widgetIndex); layoutPanel.setWidgetLeftRight(header, 0.0, Unit.PX, 0.0, Unit.PX); layoutPanel.setWidgetLeftRight(child, 0.0, Unit.PX, 0.0, Unit.PX); _LayoutData data = new _LayoutData(child, header, headerSize); if (beforeIndex < _layoutData.length) { // _layoutData.insertRange(beforeIndex, 1); // _layoutData[beforeIndex] = data; _layoutData.insert(beforeIndex, data); } else { _layoutData.add(data); } header.addStyleName(_HEADER_STYLE); child.addStyleName(_CONTENT_STYLE); header.addClickHandler(new ClickHandlerAdapter((ClickEvent event) { showWidget(child); })); header.addMouseOutHandler(new MouseOutHandlerAdapter((MouseOutEvent event) { header.removeStyleName(_HEADER_STYLE_HOVERING); })); header.addMouseOverHandler(new MouseOverHandlerAdapter((MouseOverEvent event) { header.addStyleName(_HEADER_STYLE_HOVERING); })); if (_selectedIndex == -1) { // If there's no visible widget, display the first one. The layout will // be updated onLoad(). showWidgetAt(0); } else if (beforeIndex <= _selectedIndex) { // If we inserted an item before the selected index, increment it. _selectedIndex++; } // If the widget is already attached, we must call animate() to update the // layout (if it's not yet attached, then onLoad() will do this). if (isAttached()) { animate(_animationDuration); } }
void insertAsText(Widget child, String text, bool asHtml, double headerSize, int beforeIndex) #
Inserts a widget into the panel. If the Widget is already attached, it will be moved to the requested index.
@param child the widget to be added @param text the text to be shown on its header @param asHtml <code>true</code> to treat the specified text as HTML @param headerSize the size of the header widget @param beforeIndex the index before which it will be inserted
void insertAsText(Widget child, String text, bool asHtml, double headerSize, int beforeIndex) { Html contents = new Html(); if (asHtml) { contents.html = text; } else { contents.text = text; } insert(child, new _Header(contents), headerSize, beforeIndex); }
bool isAttached() #
Returns whether or not the receiver is attached to the {@link com.google.gwt.dom.client.Document Document}'s {@link com.google.gwt.dom.client.BodyElement BodyElement}.
@return true if attached, false otherwise
bool isAttached() { if (_widget != null) { return _widget.isAttached(); } return false; }
bool isOrWasAttached() #
Has this widget ever been attached?
@return true if this widget ever been attached to the DOM, false otherwise
bool isOrWasAttached() { return eventsToSink == -1; }
Iterator<Widget> iterator() #
Returns an Iterator that iterates over this Iterable object.
Iterator<Widget> iterator() { return new _Iterator(this); }
void onAttach() #
This method is called when a widget is attached to the browser's document. To receive notification after a Widget has been added to the document, override the {@link #onLoad} method or use {@link #addAttachHandler}.
It is strongly recommended that you override {@link #onLoad()} or {@link #doAttachChildren()} instead of this method to avoid inconsistencies between logical and physical attachment states.
Subclasses that override this method must call
super.onAttach()
to ensure that the Widget has been attached
to its underlying Element.
@throws IllegalStateException if this widget is already attached @see #onLoad() @see #doAttachChildren()
void onAttach() { if (!isOrWasAttached()) { _widget.sinkEvents(eventsToSink); eventsToSink = -1; } _widget.onAttach(); // Clobber the widget's call to setEventListener(), causing all events to // be routed to this composite, which will delegate back to the widget by // default (note: it's not necessary to clear this in onDetach(), because // the widget's onDetach will do so). Dom.setEventListener(getElement(), this); // Call onLoad() directly, because we're not calling super.onAttach(). onLoad(); AttachEvent.fire(this, true); }
void onBrowserEvent(Event event) #
Fired whenever a browser event is received.
@param event the event received
TODO
void onBrowserEvent(dart_html.Event event) { // Fire any handler added to the composite itself. super.onBrowserEvent(event); // Delegate events to the widget. _widget.onBrowserEvent(event); }
void onDetach() #
This method is called when a widget is detached from the browser's document. To receive notification before a Widget is removed from the document, override the {@link #onUnload} method or use {@link #addAttachHandler}.
It is strongly recommended that you override {@link #onUnload()} or {@link #doDetachChildren()} instead of this method to avoid inconsistencies between logical and physical attachment states.
Subclasses that override this method must call
super.onDetach()
to ensure that the Widget has been detached
from the underlying Element. Failure to do so will result in application
memory leaks due to circular references between DOM Elements and JavaScript
objects.
@throws IllegalStateException if this widget is already detached @see #onUnload() @see #doDetachChildren()
void onDetach() { try { onUnload(); AttachEvent.fire(this, false); } finally { // We don't want an exception in user code to keep us from calling the // super implementation (or event listeners won't get cleaned up and // the attached flag will be wrong). _widget.onDetach(); } }
void onLoad() #
This method is called immediately after a widget becomes attached to the browser's document.
void onLoad() { // When the widget becomes attached, update its layout. animate(0); }
void onResize() #
This method must be called whenever the implementor's size has been modified.
void onResize() { layoutPanel.onResize(); }
void onUnload() #
This method is called immediately before a widget will be detached from the browser's document.
void onUnload() { }
bool remove(Widget child) #
Removes a child widget.
@param w the widget to be removed @return <code>true</code> if the widget was present
bool remove(Widget child) { if (child.getParent() != layoutPanel) { return false; } // Find the layoutData associated with this widget and remove it. for (int i = 0; i < _layoutData.length; ++i) { _LayoutData data = _layoutData[i]; if (data.widget == child) { layoutPanel.remove(data.header); layoutPanel.remove(data.widget); data.header.removeStyleName(_HEADER_STYLE); data.widget.removeStyleName(_CONTENT_STYLE); _layoutData.removeAt(i); if (_selectedIndex == i) { _selectedIndex = -1; if (_layoutData.length > 0) { showWidgetAt(getWidgetIndex(_layoutData[0].widget)); } } else { if (i <= _selectedIndex) { _selectedIndex--; } animate(_animationDuration); } return true; } } return false; }
bool removeAt(int index) #
Removes the widget at the specified index.
@param index the index of the widget to be removed @return <code>false</code> if the widget is not present
bool removeAt(int index) { return remove(getWidgetAt(index)); }
void removeFromParent() #
Removes this widget from its parent widget, if one exists.
If it has no parent, this method does nothing. If it is a "root" widget (meaning it's been added to the detach list via {@link RootPanel#detachOnWindowClose(Widget)}), it will be removed from the detached immediately. This makes it possible for Composites and Panels to adopt root widgets.
@throws IllegalStateException if this widget's parent does not support
removal (e.g. {@link Composite})
void removeFromParent() { if (_parent == null) { // If the widget had no parent, check to see if it was in the detach list // and remove it if necessary. if (RootPanel.isInDetachList(this)) { RootPanel.detachNow(this); } } else if (_parent is HasWidgets) { (_parent as HasWidgets).remove(this); } else if (_parent != null) { throw new Exception("This widget's parent does not implement HasWidgets"); } }
void removeStyleDependentName(String styleSuffix) #
Removes a dependent style name by specifying the style name's suffix.
@param styleSuffix the suffix of the dependent style to be removed @see #setStylePrimaryName(Element, String) @see #addStyleDependentName(String) @see #setStyleDependentName(String, boolean)
void removeStyleDependentName(String styleSuffix) { setStyleDependentName(styleSuffix, false); }
void removeStyleName(String style) #
Removes a style name. This method is typically used to remove secondary style names, but it can be used to remove primary stylenames as well. That use is not recommended.
@param style the secondary style name to be removed @see #addStyleName(String) @see #setStyleName(String, boolean)
void removeStyleName(String style) { setStyleName(style, false); }
void replaceElement(Element elem) #
Replaces this object's browser element.
This method exists only to support a specific use-case in Image, and should not be used by other classes.
@param elem the object's new element
void replaceElement(dart_html.Element elem) { if (isAttached()) { // Remove old event listener to avoid leaking. onDetach will not do this // for us, because it is only called when the widget itself is detached // from the document. Dom.setEventListener(getElement(), null); } super.replaceElement(elem); if (isAttached()) { // Hook the event listener back up on the new element. onAttach will not // do this for us, because it is only called when the widget itself is // attached to the document. Dom.setEventListener(getElement(), this); } }
void setAnimationDuration(int duration) #
Set the duration of the animated transition between children.
@param duration the duration in milliseconds.
void setAnimationDuration(int duration) { this._animationDuration = duration; }
void setElement(Element elem) #
Sets this object's browser element. UIObject subclasses must call this method before attempting to call any other methods, and it may only be called once.
@param elem the object's element
void setElement(dart_html.Element elem) { assert (_element == null); this._element = elem; }
void setHeaderHtml(int index, String html) #
Sets a stack header's HTML contents.
Use care when setting an object's HTML; it is an easy way to expose script-based security problems. Consider using {@link #setHeaderHTML(int, SafeHtml)} or {@link #setHeaderText(int, String)} whenever possible.
@param index the index of the header whose HTML is to be set @param html the header's new HTML contents
void setHeaderHtml(int index, String html) { checkIndex(index); _LayoutData data = _layoutData[index]; Widget headerWidget = data.header.getWidget(); assert (headerWidget is HasHtml); // : "Header widget does not implement HasHTML"; (headerWidget as HasHtml).html = html; }
void setHeaderText(int index, String text) #
Sets a stack header's text contents.
@param index the index of the header whose text is to be set @param text the object's new text
void setHeaderText(int index, String text) { checkIndex(index); _LayoutData data = _layoutData[index]; Widget headerWidget = data.header.getWidget(); assert (headerWidget is HasText); // : "Header widget does not implement HasText"; (headerWidget as HasText).text = text; }
void setHeight(String height) #
Sets the object's height. This height does not include decorations such as border, margin, and padding.
@param height the object's new height, in CSS units (e.g. "10px", "1em")
void setHeight(String height) { // This exists to deal with an inconsistency in IE's implementation where // it won't accept negative numbers in length measurements assert (extractLengthValue(height.trim().toLowerCase()) >= 0); // : "CSS heights should not be negative"; Dom.setStyleAttribute(getElement(), "height", height); }
void setLayoutData(Object value) #
Sets the panel-defined layout data associated with this widget. Only the panel that currently contains a widget should ever set this value. It serves as a place to store layout bookkeeping data associated with a widget.
@param layoutData the widget's layout data
void setLayoutData(Object value) { this._layoutData = value; }
void setParent(Widget parent) #
Sets this widget's parent. This method should only be called by {@link Panel} and {@link Composite}.
@param parent the widget's new parent @throws IllegalStateException if <code>parent</code> is non-null and the
widget already has a parent
void setParent(Widget parent) { Widget oldParent = this._parent; if (parent == null) { try { if (oldParent != null && oldParent.isAttached()) { onDetach(); assert (!isAttached()); // : "Failure of " + this.getClass().getName() + " to call super.onDetach()"; } } finally { // Put this in a finally in case onDetach throws an exception. this._parent = null; } } else { if (oldParent != null) { throw new Exception("Cannot set a new parent without first clearing the old parent"); } this._parent = parent; if (parent.isAttached()) { onAttach(); assert (isAttached()); // : "Failure of " + this.getClass().getName() + " to call super.onAttach()"; } } }
void setPixelSize(int width, int height) #
Sets the object's size, in pixels, not including decorations such as border, margin, and padding.
@param width the object's new width, in pixels @param height the object's new height, in pixels
void setPixelSize(int width, int height) { if (width >= 0) { setWidth(width.toString() + "px"); } if (height >= 0) { setHeight(height.toString() + "px"); } }
void setSize(String width, String height) #
Sets the object's size. This size does not include decorations such as border, margin, and padding.
@param width the object's new width, in CSS units (e.g. "10px", "1em") @param height the object's new height, in CSS units (e.g. "10px", "1em")
void setSize(String width, String height) { setWidth(width); setHeight(height); }
void setStyleDependentName(String styleSuffix, bool add) #
Adds or removes a dependent style name by specifying the style name's suffix. The actual form of the style name that is added is:
getStylePrimaryName() + '-' + styleSuffix
@param styleSuffix the suffix of the dependent style to be added or removed @param add <code>true</code> to add the given style, <code>false</code> to
remove it
@see #setStylePrimaryName(Element, String) @see #addStyleDependentName(String) @see #setStyleName(String, boolean) @see #removeStyleDependentName(String)
void setStyleDependentName(String styleSuffix, bool add) { setStyleName(getStylePrimaryName() + '-' + styleSuffix, add); }
void setStyleName(String style, bool add) #
Adds or removes a style name. This method is typically used to remove secondary style names, but it can be used to remove primary stylenames as well. That use is not recommended.
@param style the style name to be added or removed @param add <code>true</code> to add the given style, <code>false</code> to
remove it
@see #addStyleName(String) @see #removeStyleName(String)
void setStyleName(String style, bool add) { manageElementStyleName(getStyleElement(), style, add); }
void setStylePrimaryName(String style) #
Sets the object's primary style name and updates all dependent style names.
@param style the new primary style name @see #addStyleName(String) @see #removeStyleName(String)
void setStylePrimaryName(String style) { setElementStylePrimaryName(getStyleElement(), style); }
void setWidth(String width) #
Sets the object's width. This width does not include decorations such as border, margin, and padding.
@param width the object's new width, in CSS units (e.g. "10px", "1em")
void setWidth(String width) { // This exists to deal with an inconsistency in IE's implementation where // it won't accept negative numbers in length measurements assert (extractLengthValue(width.trim().toLowerCase()) >= 0); // : "CSS widths should not be negative"; Dom.setStyleAttribute(getElement(), "width", width); }
void showWidget(Widget child, [bool fireEvents = false]) #
Shows the specified widget.
@param child the child widget to be shown. @param fireEvents true to fire events, false not to
void showWidget(Widget child, [bool fireEvents = false]) { showWidgetAt(getWidgetIndex(child), _animationDuration, fireEvents); }
void showWidgetAt(int index, [int duration = null, bool fireEvents = false]) #
void showWidgetAt(int index, [int duration = null, bool fireEvents = false]) { checkIndex(index); if (index == _selectedIndex) { return; } // Fire the before selection event, giving the recipients a chance to // cancel the selection. if (fireEvents) { BeforeSelectionEvent<int> event = BeforeSelectionEvent.fire(this, index); if ((event != null) && event.isCanceled()) { return; } } _selectedIndex = index; if (isAttached()) { animate(duration == null ? _animationDuration : duration); } // Fire the selection event. if (fireEvents) { SelectionEvent.fire(this, index); } }
void sinkBitlessEvent(String eventTypeName) #
Sinks a named event. Note that only {@link Widget widgets} may actually receive events, but can receive events from all objects contained within them.
@param eventTypeName name of the event to sink on this element @see com.google.gwt.user.client.Event
void sinkBitlessEvent(String eventTypeName) { Dom.sinkBitlessEvent(getElement(), eventTypeName); }
void sinkEvents(int eventBitsToAdd) #
Overridden to defer the call to super.sinkEvents until the first time this widget is attached to the dom, as a performance enhancement. Subclasses wishing to customize sinkEvents can preserve this deferred sink behavior by putting their implementation behind a check of <code>isOrWasAttached()</code>:
{@literal @}Override public void sinkEvents(int eventBitsToAdd) { if (isOrWasAttached()) { /{@literal *} customized sink code goes here {@literal *}/ } else { super.sinkEvents(eventBitsToAdd); } }
void sinkEvents(int eventBitsToAdd) { if (isOrWasAttached()) { super.sinkEvents(eventsToSink); } else { eventsToSink |= eventBitsToAdd; } }
String toString() #
This method is overridden so that any object can be viewed in the debugger as an HTML snippet.
@return a string representation of the object
String toString() { if (_element == null) { return "(null handle)"; } return getElement().toString(); }
void unsinkEvents(int eventBitsToRemove) #
Removes a set of events from this object's event list.
@param eventBitsToRemove a bitfield representing the set of events to be
removed from this element's event set
@see #sinkEvents @see com.google.gwt.user.client.Event
void unsinkEvents(int eventBitsToRemove) { Dom.sinkEvents(getElement(), Dom.getEventsSunk(getElement()) & (~eventBitsToRemove)); }