+/*
+TODO
+- separate styles to proper places
+- decide a good class name structure for core layouts (e.g. 'v-layout', 'v-vertical', 'v-grid' etc.)
+- use !important in carefully selected places to prevent accidental layout breakage by custom theming (e.g. alignments should be forced)
+
+*/
+
.v-boxlayout.v-margin-top {padding-top: 18px;}
.v-boxlayout.v-margin-right {padding-right: 18px;}
.v-boxlayout.v-margin-bottom {padding-bottom: 18px;}
}
.v-boxlayout.v-horizontal {
- white-space: nowrap;
+ white-space: nowrap !important;
}
.v-boxlayout > .v-expand {
}
.v-caption {
+ display: inline-block; /* Force default width to zero */
overflow: visible;
vertical-align: middle;
}
white-space: nowrap;
}
-.v-caption-on-left > .v-caption,
-.v-caption-on-right > .v-caption {
- display: inline-block;
+.v-caption-on-top > .v-caption,
+.v-caption-on-bottom > .v-caption {
+ display: block;
}
.v-caption-on-left > .v-caption {
.v-has-caption.v-has-height > .v-paintable {
height: 100% !important;
+}
+
+.v-errorindicator {
+ vertical-align: middle;
}
\ No newline at end of file
import com.vaadin.terminal.gwt.client.communication.RpcProxy;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
import com.vaadin.terminal.gwt.client.communication.StateChangeEvent.StateChangeHandler;
+import com.vaadin.terminal.gwt.client.ui.VBoxLayout.CaptionPosition;
import com.vaadin.terminal.gwt.client.ui.VBoxLayout.Slot;
import com.vaadin.terminal.gwt.client.ui.layout.ElementResizeEvent;
import com.vaadin.terminal.gwt.client.ui.layout.ElementResizeListener;
private HashMap<Element, Integer> childCaptionElementHeight = new HashMap<Element, Integer>();
// For debugging
- private int resizeCount = 0;
+ private static int resizeCount = 0;
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
if (!isRealUpdate(uidl)) {
slot.setAlignment(alignment);
double expandRatio;
- if (expandRatios.containsKey(pid)
+ // TODO discuss the layout specs, is this what we want: distribute
+ // extra space equally if no expand ratios are specified inside a
+ // layout with specified size
+ if (expandRatios.getKeySet().size() == 0
+ && ((!getWidget().vertical && !isUndefinedHeight()) || !isUndefinedWidth())) {
+ expandRatio = 1;
+ hasExpandRatio.add(child);
+ } else if (expandRatios.containsKey(pid)
&& expandRatios.getRawNumber(pid) > 0) {
expandRatio = expandRatios.getRawNumber(pid);
hasExpandRatio.add(child);
}
slot.setExpandRatio(expandRatio);
+ if (slot.getSpacingElement() != null) {
+ getLayoutManager().addElementResizeListener(
+ slot.getSpacingElement(), spacingResizeListener);
+ }
+
}
if (needsExpand()) {
.getIcon().getURL() : null;
List<String> styles = child.getState().getStyles();
String error = child.getState().getErrorMessage();
+ boolean required = false;
+ if (child instanceof AbstractFieldConnector) {
+ required = ((AbstractFieldConnector) child).isRequired();
+ }
// TODO Description is handled from somewhere else?
- slot.setCaption(caption, iconUrl, styles, error);
+ slot.setCaption(caption, iconUrl, styles, error, required);
slot.setRelativeWidth(child.isRelativeWidth());
slot.setRelativeHeight(child.isRelativeHeight());
- // TODO Should also check captionposition: && captionPosition==TOP ||
- // captionPosition==BOTTOM
if (slot.hasCaption()) {
+ CaptionPosition pos = slot.getCaptionPosition();
getLayoutManager().addElementResizeListener(
slot.getCaptionElement(), slotCaptionResizeListener);
+ if (child.isRelativeHeight()
+ && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) {
+ getWidget().updateCaptionOffset(slot.getCaptionElement());
+ } else if (child.isRelativeWidth()
+ && (pos == CaptionPosition.LEFT || pos == CaptionPosition.RIGHT)) {
+ getWidget().updateCaptionOffset(slot.getCaptionElement());
+ }
} else {
getLayoutManager().removeElementResizeListener(
slot.getCaptionElement(), slotCaptionResizeListener);
slot.getCaptionElement(),
slotCaptionResizeListener);
}
+ if (slot.getSpacingElement() != null) {
+ getLayoutManager().removeElementResizeListener(
+ slot.getSpacingElement(), spacingResizeListener);
+ }
layout.removeSlot(child.getWidget());
}
}
Slot slot = getWidget().getSlot(child.getWidget());
slot.setRelativeWidth(child.isRelativeWidth());
slot.setRelativeHeight(child.isRelativeHeight());
- if (slot.hasCaption() && child.isRelativeHeight()) {
- getWidget().updateCaptionOffset(slot.getCaptionElement());
+
+ // For relative sized widgets, we need to set the caption offset
+ if (slot.hasCaption()) {
+ CaptionPosition pos = slot.getCaptionPosition();
+ if (child.isRelativeHeight()
+ && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) {
+ getWidget().updateCaptionOffset(slot.getCaptionElement());
+ } else if (child.isRelativeWidth()
+ && (pos == CaptionPosition.LEFT || pos == CaptionPosition.RIGHT)) {
+ getWidget().updateCaptionOffset(slot.getCaptionElement());
+ }
}
+ // TODO 'needsExpand' might return false during the first render,
+ // since updateFromUidl is called last
+
// If the slot has caption, we need to listen for it's size changes
// in order to update the padding/margin offset for relative sized
// components
getLayoutManager().addElementResizeListener(
slot.getCaptionElement(), slotCaptionResizeListener);
} else if (!needsExpand()) {
- getLayoutManager().removeElementResizeListener(
- slot.getCaptionElement(), slotCaptionResizeListener);
+ // getLayoutManager().removeElementResizeListener(
+ // slot.getCaptionElement(), slotCaptionResizeListener);
+ }
+
+ if (slot.getSpacingElement() != null && needsExpand()) {
+ // Spacing is on
+ getLayoutManager().addElementResizeListener(
+ slot.getSpacingElement(), spacingResizeListener);
+ } else if (slot.getSpacingElement() != null) {
+ getLayoutManager().addElementResizeListener(
+ slot.getSpacingElement(), spacingResizeListener);
}
if (child.isRelativeHeight()) {
hasRelativeHeight.add(child);
needsMeasure.remove(child.getWidget().getElement());
- // childElementHeight.remove(child.getWidget().getElement());
} else {
hasRelativeHeight.remove(child);
needsMeasure.add(child.getWidget().getElement());
Element captionElement = (Element) e.getElement().cast();
- // TODO take caption position into account
+ CaptionPosition pos = getWidget().getCaptionPositionFromElement(
+ (Element) captionElement.getParentElement().cast());
+
Element widgetElement = captionElement.getParentElement()
.getLastChild().cast();
+ if (pos == CaptionPosition.BOTTOM || pos == CaptionPosition.RIGHT) {
+ widgetElement = captionElement.getParentElement()
+ .getFirstChildElement().cast();
+ }
if (captionElement == widgetElement) {
// Caption element already detached
return;
}
+ String widgetWidth = widgetElement.getStyle().getWidth();
String widgetHeight = widgetElement.getStyle().getHeight();
- if (widgetHeight.endsWith("%")) {
+
+ if (widgetHeight.endsWith("%")
+ && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) {
+ getWidget().updateCaptionOffset(captionElement);
+ } else if (widgetWidth.endsWith("%")
+ && (pos == CaptionPosition.LEFT || pos == CaptionPosition.RIGHT)) {
getWidget().updateCaptionOffset(captionElement);
}
}
};
+ private ElementResizeListener spacingResizeListener = new ElementResizeListener() {
+ public void onElementResize(ElementResizeEvent e) {
+ resizeCount++;
+ if (needsExpand()) {
+ updateExpand();
+ }
+ }
+ };
+
private void updateLayoutHeight() {
if (needsFixedHeight() && childElementHeight.size() > 0) {
int h = getMaxHeight();
}
private void updateExpand() {
- System.out.println("All sizes: "
- + childElementHeight.values().toString() + " - Caption sizes: "
- + childCaptionElementHeight.values().toString());
+ // System.out.println("All sizes: "
+ // + childElementHeight.values().toString() + " - Caption sizes: "
+ // + childCaptionElementHeight.values().toString());
getWidget().updateExpand();
}
int highestNonRelative = -1;
int highestRelative = -1;
for (Element el : childElementHeight.keySet()) {
+ // TODO would be more efficient to measure the slot element if both
+ // caption and child widget elements need to be measured. Keeping
+ // track of what to measure is the most difficult part of this
+ // layout.
+ CaptionPosition pos = getWidget().getCaptionPositionFromElement(
+ (Element) el.getParentElement().cast());
if (needsMeasure.contains(el)) {
int h = childElementHeight.get(el);
String sHeight = el.getStyle().getHeight();
+ // Only add the caption size to the height of the slot if
+ // coption position is top or bottom
if (childCaptionElementHeight.containsKey(el)
- && (sHeight == null || !sHeight.endsWith("%"))) {
+ && (sHeight == null || !sHeight.endsWith("%"))
+ && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) {
h += childCaptionElementHeight.get(el);
}
if (h > highestNonRelative) {
}
} else {
int h = childElementHeight.get(el);
- if (childCaptionElementHeight.containsKey(el)) {
+ if (childCaptionElementHeight.containsKey(el)
+ && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM)) {
h += childCaptionElementHeight.get(el);
}
if (h > highestRelative) {
slot.getCaptionElement(), slotCaptionResizeListener);
}
+ if (slot.getSpacingElement() != null) {
+ getLayoutManager().removeElementResizeListener(
+ slot.getSpacingElement(), spacingResizeListener);
+ }
+
getLayoutManager()
.removeElementResizeListener(slot.getWidget().getElement(),
childComponentResizeListener);
private Element captionText;
private Icon icon;
private Element errorIcon;
+ private Element requiredIcon;
- private CaptionPosition captionPosition = CaptionPosition.TOP;
+ // Caption is placed after component unless there is some part which
+ // moves it above.
+ private CaptionPosition captionPosition = CaptionPosition.RIGHT;
private AlignmentInfo alignment;
private double expandRatio = -1;
}
protected int getSpacingSize(boolean vertical) {
- // No spacer attached
if (spacer == null) {
return 0;
}
- // if (layoutManager != null) {
- // return vertical ? layoutManager.getOuterHeight(spacer)
- // : layoutManager.getOuterWidth(spacer);
- // } else {
+ if (layoutManager != null) {
+ if (vertical) {
+ return layoutManager.getOuterHeight(spacer);
+ } else {
+ return layoutManager.getOuterWidth(spacer);
+ }
+ }
// TODO place for optimization (in expense of theme
// flexibility): only measure one of the elements and cache the
// value
}
public void setCaptionPosition(CaptionPosition captionPosition) {
- this.captionPosition = captionPosition;
if (caption == null) {
return;
}
+
+ captionWrap.removeClassName("v-caption-on-"
+ + this.captionPosition.name().toLowerCase());
+
+ this.captionPosition = captionPosition;
if (captionPosition == CaptionPosition.BOTTOM
|| captionPosition == CaptionPosition.RIGHT) {
captionWrap.appendChild(caption);
} else {
captionWrap.insertFirst(caption);
}
+
captionWrap.addClassName("v-caption-on-"
+ captionPosition.name().toLowerCase());
}
+ public CaptionPosition getCaptionPosition() {
+ return captionPosition;
+ }
+
public void setCaption(String captionText, String iconUrl,
- List<String> styles, String error) {
+ List<String> styles, String error, boolean required) {
// TODO place for optimization: check if any of these have changed
// since last time, and only run those changes
// Caption wrappers
- if (captionText != null || iconUrl != null || error != null) {
+ if (captionText != null || iconUrl != null || error != null
+ || required) {
if (caption == null) {
caption = DOM.createDiv();
captionWrap = DOM.createDiv();
captionWrap.addClassName("v-has-caption");
getElement().appendChild(captionWrap);
captionWrap.appendChild(getWidget().getElement());
- setCaptionPosition(captionPosition);
}
} else if (caption != null) {
getElement().appendChild(getWidget().getElement());
errorIcon = null;
}
+ // Required
+ if (required) {
+ if (requiredIcon == null) {
+ requiredIcon = DOM.createSpan();
+ requiredIcon.setClassName("v-required-indicator");
+ }
+ caption.appendChild(requiredIcon);
+ } else if (requiredIcon != null) {
+ requiredIcon.removeFromParent();
+ requiredIcon = null;
+ }
+
// Styles
if (caption != null) {
caption.setClassName("v-caption");
}
}
+ if (caption != null) {
+ if (captionText != null || iconUrl != null) {
+ setCaptionPosition(CaptionPosition.TOP);
+ } else {
+ setCaptionPosition(CaptionPosition.RIGHT);
+ }
+ }
+
// TODO theme flexibility: add extra styles to captionWrap as well?
}
private static final RegExp captionPositionRegexp = RegExp
.compile("v-caption-on-(\\S+)");
+ CaptionPosition getCaptionPositionFromElement(Element captionWrap) {
+ // Get caption position from the classname
+ MatchResult matcher = captionPositionRegexp.exec(captionWrap
+ .getClassName());
+ if (matcher == null || matcher.getGroupCount() < 2) {
+ return CaptionPosition.TOP;
+ }
+ String captionClass = matcher.getGroup(1);
+ CaptionPosition captionPosition = CaptionPosition.valueOf(
+ CaptionPosition.class, captionClass.toUpperCase());
+ return captionPosition;
+ }
+
void updateCaptionOffset(Element caption) {
Element captionWrap = caption.getParentElement().cast();
captionStyle.clearMarginLeft();
// Get caption position from the classname
- MatchResult matcher = captionPositionRegexp.exec(captionWrap
- .getClassName());
- String captionClass = matcher.getGroup(1);
- CaptionPosition captionPosition = CaptionPosition.valueOf(
- CaptionPosition.class, captionClass.toUpperCase());
+ CaptionPosition captionPosition = getCaptionPositionFromElement(captionWrap);
if (captionPosition == CaptionPosition.LEFT
|| captionPosition == CaptionPosition.RIGHT) {
} else {
captionWidth = caption.getOffsetWidth();
}
- if (captionPosition == CaptionPosition.LEFT) {
- captionWrapStyle.setPaddingLeft(captionWidth, Unit.PX);
- captionStyle.setMarginLeft(-captionWidth, Unit.PX);
- } else {
- captionWrapStyle.setPaddingRight(captionWidth, Unit.PX);
- captionStyle.setMarginRight(-captionWidth, Unit.PX);
+ if (captionWidth > 0) {
+ if (captionPosition == CaptionPosition.LEFT) {
+ captionWrapStyle.setPaddingLeft(captionWidth, Unit.PX);
+ captionStyle.setMarginLeft(-captionWidth, Unit.PX);
+ } else {
+ captionWrapStyle.setPaddingRight(captionWidth, Unit.PX);
+ captionStyle.setMarginRight(-captionWidth, Unit.PX);
+ }
}
}
if (captionPosition == CaptionPosition.TOP
} else {
captionHeight = caption.getOffsetHeight();
}
- if (captionPosition == CaptionPosition.TOP) {
- captionWrapStyle.setPaddingTop(captionHeight, Unit.PX);
- captionStyle.setMarginTop(-captionHeight, Unit.PX);
- } else {
- captionWrapStyle.setPaddingBottom(captionHeight, Unit.PX);
- captionStyle.setMarginBottom(-captionHeight, Unit.PX);
+ if (captionHeight > 0) {
+ if (captionPosition == CaptionPosition.TOP) {
+ captionWrapStyle.setPaddingTop(captionHeight, Unit.PX);
+ captionStyle.setMarginTop(-captionHeight, Unit.PX);
+ } else {
+ captionWrapStyle.setPaddingBottom(captionHeight, Unit.PX);
+ captionStyle.setMarginBottom(-captionHeight, Unit.PX);
+ }
}
}
}
slot.getElement().getStyle().clearMarginLeft();
slot.getElement().getStyle().clearMarginTop();
}
+
if (isExpanding) {
- if (expandWrapper == null) {
- expandWrapper = DOM.createDiv();
- expandWrapper.setClassName("v-expand");
- for (; getElement().getChildCount() > 0;) {
- Node el = getElement().getChild(0);
- expandWrapper.appendChild(el);
+ if (isExpanding) {
+ if (expandWrapper == null) {
+ expandWrapper = DOM.createDiv();
+ expandWrapper.setClassName("v-expand");
+ for (; getElement().getChildCount() > 0;) {
+ Node el = getElement().getChild(0);
+ expandWrapper.appendChild(el);
+ }
+ getElement().appendChild(expandWrapper);
}
- getElement().appendChild(expandWrapper);
- }
-
- int totalSize = 0;
- for (Widget w : getChildren()) {
- Slot slot = (Slot) w;
- if (slot.getExpandRatio() == -1) {
- if (layoutManager != null) {
- // TODO check caption position
- if (vertical) {
- totalSize += layoutManager.getOuterHeight(slot
- .getWidget().getElement())
- - layoutManager.getMarginHeight(slot
- .getWidget().getElement());
- if (slot.hasCaption()) {
+
+ int totalSize = 0;
+ for (Widget w : getChildren()) {
+ Slot slot = (Slot) w;
+ if (slot.getExpandRatio() == -1) {
+ if (layoutManager != null) {
+ // TODO check caption position
+ if (vertical) {
totalSize += layoutManager.getOuterHeight(slot
- .getCaptionElement())
+ .getWidget().getElement())
- layoutManager.getMarginHeight(slot
- .getCaptionElement());
+ .getWidget().getElement());
+ if (slot.hasCaption()) {
+ totalSize += layoutManager
+ .getOuterHeight(slot
+ .getCaptionElement())
+ - layoutManager
+ .getMarginHeight(slot
+ .getCaptionElement());
+ }
+ } else {
+ totalSize += layoutManager.getOuterWidth(slot
+ .getWidget().getElement())
+ - layoutManager.getMarginWidth(slot
+ .getWidget().getElement());
}
} else {
- totalSize += layoutManager.getOuterWidth(slot
- .getWidget().getElement())
- - layoutManager.getMarginWidth(slot
- .getWidget().getElement());
+ totalSize += vertical ? slot.getOffsetHeight()
+ : slot.getOffsetWidth();
}
- } else {
- totalSize += vertical ? slot.getOffsetHeight() : slot
- .getOffsetWidth();
}
+ // TODO fails in Opera, always returns 0
+ totalSize += slot.getSpacingSize(vertical);
}
- // TODO fails in Opera, always returns 0
- totalSize += slot.getSpacingSize(vertical);
- }
-
- // When we set the margin to the first child, we don't need
- // overflow:hidden in the layout root element, since the wrapper
- // would otherwise be placed outside of the layout root element
- // and block events on elements below it.
- if (vertical) {
- expandWrapper.getStyle().setPaddingTop(totalSize, Unit.PX);
- expandWrapper.getFirstChildElement().getStyle()
- .setMarginTop(-totalSize, Unit.PX);
- } else {
- expandWrapper.getStyle().setPaddingLeft(totalSize, Unit.PX);
- expandWrapper.getFirstChildElement().getStyle()
- .setMarginLeft(-totalSize, Unit.PX);
- }
- recalculateExpands();
+ // When we set the margin to the first child, we don't need
+ // overflow:hidden in the layout root element, since the wrapper
+ // would otherwise be placed outside of the layout root element
+ // and block events on elements below it.
+ if (vertical) {
+ expandWrapper.getStyle().setPaddingTop(totalSize, Unit.PX);
+ expandWrapper.getFirstChildElement().getStyle()
+ .setMarginTop(-totalSize, Unit.PX);
+ } else {
+ expandWrapper.getStyle().setPaddingLeft(totalSize, Unit.PX);
+ expandWrapper.getFirstChildElement().getStyle()
+ .setMarginLeft(-totalSize, Unit.PX);
+ }
+ recalculateExpands();
+
+ }
}
}
--- /dev/null
+package com.vaadin.tests.components.orderedlayout;
+
+import com.vaadin.annotations.Theme;
+import com.vaadin.terminal.Sizeable;
+import com.vaadin.terminal.ThemeResource;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.tests.components.AbstractTestRoot;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.Embedded;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.HorizontalSplitPanel;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.NativeButton;
+import com.vaadin.ui.NativeSelect;
+import com.vaadin.ui.Slider;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.VerticalLayout;
+
+@Theme("tests-components")
+public class VaadinTunesLayout extends AbstractTestRoot {
+
+ @Override
+ public void setup(WrappedRequest request) {
+
+ /*
+ * We'll build the whole UI here, since the application will not contain
+ * any logic. Otherwise it would be more practical to separate parts of
+ * the UI into different classes and methods.
+ */
+
+ // Main (browser) window, needed in all Vaadin applications
+ VerticalLayout rootLayout = new VerticalLayout();
+ // final Window root = new Window("VaadinTunes", rootLayout);
+
+ /*
+ * We'll attach the window to the browser view already here, so we won't
+ * forget it later.
+ */
+ setContent(rootLayout);
+
+ // root.showNotification(
+ // "This is an example of how you can do layouts in Vaadin.<br/>It is not a working sound player.",
+ // Notification.TYPE_HUMANIZED_MESSAGE);
+
+ // Our root window contains one VerticalLayout, let's make
+ // sure it's 100% sized, and remove unwanted margins
+ rootLayout.setSizeFull();
+ rootLayout.setMargin(false);
+
+ // Top area, containing playback and volume controls, play status, view
+ // modes and search
+ HorizontalLayout top = new HorizontalLayout();
+ top.setWidth("100%");
+ top.setMargin(false, true, false, true); // Enable horizontal margins
+ top.setSpacing(true);
+
+ // Let's attach that one straight away too
+ rootLayout.addComponent(top);
+
+ // Create the placeholders for all the components in the top area
+ HorizontalLayout playback = new HorizontalLayout();
+ HorizontalLayout volume = new HorizontalLayout();
+ HorizontalLayout status = new HorizontalLayout();
+ HorizontalLayout viewmodes = new HorizontalLayout();
+ ComboBox search = new ComboBox();
+
+ // Add the components and align them properly
+ top.addComponent(playback);
+ top.addComponent(volume);
+ top.addComponent(status);
+ top.addComponent(viewmodes);
+ top.addComponent(search);
+ top.setComponentAlignment(playback, Alignment.MIDDLE_LEFT);
+ top.setComponentAlignment(volume, Alignment.MIDDLE_LEFT);
+ top.setComponentAlignment(status, Alignment.MIDDLE_CENTER);
+ top.setComponentAlignment(viewmodes, Alignment.MIDDLE_LEFT);
+ top.setComponentAlignment(search, Alignment.MIDDLE_LEFT);
+
+ /*
+ * We want our status area to expand if the user resizes the root
+ * window, and we want it to accommodate as much space as there is
+ * available. All other components in the top layout should stay fixed
+ * sized, so we don't need to specify any expand ratios for them (they
+ * will automatically revert to zero after the following line).
+ */
+ top.setExpandRatio(status, 1.0F);
+
+ // Playback controls
+ Button prev = new NativeButton("Previous");
+ Button play = new NativeButton("Play/pause");
+ Button next = new NativeButton("Next");
+ playback.addComponent(prev);
+ playback.addComponent(play);
+ playback.addComponent(next);
+ // Set spacing between the buttons
+ playback.setSpacing(true);
+
+ // Volume controls
+ Button mute = new NativeButton("mute");
+ Slider vol = new Slider();
+ vol.setOrientation(Slider.ORIENTATION_HORIZONTAL);
+ vol.setWidth("100px");
+ Button max = new NativeButton("max");
+ volume.addComponent(mute);
+ volume.addComponent(vol);
+ volume.addComponent(max);
+
+ // Status area
+ status.setWidth("80%");
+ status.setSpacing(true);
+
+ Button toggleVisualization = new NativeButton("Mode");
+ Label timeFromStart = new Label("0:00");
+
+ // We'll need another layout to show currently playing track and
+ // progress
+ VerticalLayout trackDetails = new VerticalLayout();
+ trackDetails.setWidth("100%");
+ Label track = new Label("Track Name");
+ Label album = new Label("Album Name - Artist");
+ track.setWidth(null);
+ album.setWidth(null);
+ Slider progress = new Slider();
+ progress.setOrientation(Slider.ORIENTATION_HORIZONTAL);
+ progress.setWidth("100%");
+ trackDetails.addComponent(track);
+ trackDetails.addComponent(album);
+ trackDetails.addComponent(progress);
+ trackDetails.setComponentAlignment(track, Alignment.TOP_CENTER);
+ trackDetails.setComponentAlignment(album, Alignment.TOP_CENTER);
+
+ Label timeToEnd = new Label("-4:46");
+ Button jumpToTrack = new NativeButton("Show");
+
+ // Place all components to the status layout and align them properly
+ status.addComponent(toggleVisualization);
+ status.setComponentAlignment(toggleVisualization, Alignment.MIDDLE_LEFT);
+ status.addComponent(timeFromStart);
+ status.setComponentAlignment(timeFromStart, Alignment.BOTTOM_LEFT);
+ status.addComponent(trackDetails);
+ status.addComponent(timeToEnd);
+ status.setComponentAlignment(timeToEnd, Alignment.BOTTOM_LEFT);
+ status.addComponent(jumpToTrack);
+ status.setComponentAlignment(jumpToTrack, Alignment.MIDDLE_LEFT);
+
+ // Then remember to specify the expand ratio
+ status.setExpandRatio(trackDetails, 1.0F);
+
+ // View mode buttons
+ Button viewAsTable = new NativeButton("Table");
+ Button viewAsGrid = new NativeButton("Grid");
+ Button coverflow = new NativeButton("Coverflow");
+ viewmodes.addComponent(viewAsTable);
+ viewmodes.addComponent(viewAsGrid);
+ viewmodes.addComponent(coverflow);
+
+ /*
+ * That covers the top bar. Now let's move on to the sidebar and track
+ * listing
+ */
+
+ // We'll need one splitpanel to separate the sidebar and track listing
+ HorizontalSplitPanel bottom = new HorizontalSplitPanel();
+ rootLayout.addComponent(bottom);
+
+ // The splitpanel is by default 100% x 100%, but we'll need to adjust
+ // our main window layout to accomodate the height
+ rootLayout.setExpandRatio(bottom, 1.0F);
+
+ // Give the sidebar less space than the listing
+ bottom.setSplitPosition(200, Sizeable.UNITS_PIXELS);
+
+ // Let's add some content to the sidebar
+ // First, we need a layout to but all components in
+ VerticalLayout sidebar = new VerticalLayout();
+ sidebar.setSizeFull();
+ bottom.setFirstComponent(sidebar);
+
+ /*
+ * Then we need some labels and buttons, and an album cover image The
+ * labels and buttons go into their own vertical layout, since we want
+ * the 'sidebar' layout to be expanding (cover image in the bottom).
+ * VerticalLayout is by default 100% wide.
+ */
+ VerticalLayout selections = new VerticalLayout();
+ Label library = new Label("Library");
+ Button music = new NativeButton("Music");
+ music.setWidth("100%");
+
+ Label store = new Label("Store");
+ Button vaadinTunesStore = new NativeButton("VaadinTunes Store");
+ vaadinTunesStore.setWidth("100%");
+ Button purchased = new NativeButton("Purchased");
+ purchased.setWidth("100%");
+
+ Label playlists = new Label("Playlists");
+ Button genius = new NativeButton("Geniues");
+ genius.setWidth("100%");
+ Button recent = new NativeButton("Recently Added");
+ recent.setWidth("100%");
+
+ // Lets add them to the 'selections' layout
+ selections.addComponent(library);
+ selections.addComponent(music);
+ selections.addComponent(store);
+ selections.addComponent(vaadinTunesStore);
+ selections.addComponent(purchased);
+ selections.addComponent(playlists);
+ selections.addComponent(genius);
+ selections.addComponent(recent);
+
+ // Then add the selections to the sidebar, and set it expanding
+ sidebar.addComponent(selections);
+ sidebar.setExpandRatio(selections, 1.0F);
+
+ // Then comes the cover artwork (we'll add the actual image in the
+ // themeing section)
+ Embedded cover = new Embedded("Currently Playing");
+ sidebar.addComponent(cover);
+
+ /*
+ * And lastly, we need the track listing table It should fill the whole
+ * left side of our bottom layout
+ */
+ Table listing = new Table();
+ listing.setSizeFull();
+ listing.setSelectable(true);
+ bottom.setSecondComponent(listing);
+
+ // Add the table headers
+ listing.addContainerProperty("Name", String.class, "");
+ listing.addContainerProperty("Time", String.class, "0:00");
+ listing.addContainerProperty("Artist", String.class, "");
+ listing.addContainerProperty("Album", String.class, "");
+ listing.addContainerProperty("Genre", String.class, "");
+ listing.addContainerProperty("Rating", NativeSelect.class,
+ new NativeSelect());
+
+ // Lets populate the table with random data
+ String[] tracks = new String[] { "Red Flag", "Millstone",
+ "Not The Sun", "Breath", "Here We Are", "Deep Heaven",
+ "Her Voice Resides", "Natural Tan", "End It All", "Kings",
+ "Daylight Slaving", "Mad Man", "Resolve", "Teargas",
+ "African Air", "Passing Bird" };
+ String[] times = new String[] { "4:12", "6:03", "5:43", "4:32", "3:42",
+ "4:45", "2:56", "9:34", "2:10", "3:44", "5:49", "6:30", "5:18",
+ "7:42", "3:13", "2:52" };
+ String[] artists = new String[] { "Billy Talent", "Brand New",
+ "Breaking Benjamin", "Becoming The Archetype",
+ "Bullet For My Valentine", "Chasing Victory", "Chimaira",
+ "Danko Jones", "Deadlock", "Deftones", "From Autumn To Ashes",
+ "Haste The Day", "Four Year Strong", "In Flames", "Kemopetrol",
+ "John Legend" };
+ String[] albums = new String[] { "Once Again", "The Caitiff Choir",
+ "The Devil And God", "Light Grenades", "Dicthonomy",
+ "Back In Black", "Dreamer", "Come Clarity", "Year Zero",
+ "Frames", "Fortress", "Phobia", "The Poison", "Manifesto",
+ "White Pony", "The Big Dirty" };
+ String[] genres = new String[] { "Rock", "Metal", "Hardcore", "Indie",
+ "Pop", "Alternative", "Blues", "Jazz", "Hip Hop",
+ "Electronica", "Punk", "Hard Rock", "Dance", "R'n'B", "Gospel",
+ "Country" };
+ for (int i = 0; i < 1000; i++) {
+ NativeSelect s = new NativeSelect();
+ s.addItem("1 star");
+ s.addItem("2 stars");
+ s.addItem("3 stars");
+ s.addItem("4 stars");
+ s.addItem("5 stars");
+ s.select(i % 5 + " stars");
+ final int index = i % 16;
+ listing.addItem(new Object[] { tracks[index], times[index],
+ artists[index], albums[index], genres[index], s }, i);
+ }
+
+ // We'll align the track time column to right as well
+ listing.setColumnAlignment("Time", Table.ALIGN_RIGHT);
+
+ // TODO the footer
+
+ // Now what's left to do? Themeing of course.
+ // setTheme("vaadintunes");
+
+ /*
+ * Let's give a namespace to our application window. This way, if
+ * someone uses the same theme for different applications, we don't get
+ * unwanted style conflicts.
+ */
+ // root.setStyleName("tTunes");
+
+ top.setStyleName("top");
+ top.setHeight("75px"); // Same as the background image height
+
+ playback.setStyleName("playback");
+ playback.setMargin(false, true, false, false); // Add right-side margin
+ play.setStyleName("play");
+ next.setStyleName("next");
+ prev.setStyleName("prev");
+ playback.setComponentAlignment(prev, Alignment.MIDDLE_LEFT);
+ playback.setComponentAlignment(next, Alignment.MIDDLE_LEFT);
+
+ volume.setStyleName("volume");
+ mute.setStyleName("mute");
+ max.setStyleName("max");
+ vol.setWidth("78px");
+
+ status.setStyleName("status");
+ status.setMargin(true);
+ status.setHeight("46px"); // Height of the background image
+
+ toggleVisualization.setStyleName("toggle-vis");
+ jumpToTrack.setStyleName("jump");
+
+ viewAsTable.setStyleName("viewmode-table");
+ viewAsGrid.setStyleName("viewmode-grid");
+ coverflow.setStyleName("viewmode-coverflow");
+
+ sidebar.setStyleName("sidebar");
+
+ music.setStyleName("selected");
+
+ cover.setSource(new ThemeResource("images/album-cover.jpg"));
+ // Because this is an image, it will retain it's aspect ratio
+ cover.setWidth("100%");
+ }
+
+ @Override
+ protected String getTestDescription() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
\ No newline at end of file