1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 package info.magnolia.ui.field;
34
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import com.vaadin.data.HasValue;
39 import com.vaadin.shared.Registration;
40 import com.vaadin.shared.ui.MarginInfo;
41 import com.vaadin.ui.Component;
42 import com.vaadin.ui.CustomField;
43 import com.vaadin.ui.HorizontalLayout;
44 import com.vaadin.ui.Label;
45 import com.vaadin.ui.Layout;
46 import com.vaadin.ui.Slider;
47 import com.vaadin.ui.VerticalLayout;
48
49
50
51
52 public class SliderField extends CustomField<Double> {
53
54 private static final Logger log = LoggerFactory.getLogger(SliderField.class);
55
56 private final SliderFieldDefinition definition;
57 private final Label sliderValueLabel;
58 private final Slider slider;
59
60 public SliderField(SliderFieldDefinition definition) {
61 double stepSize = definition.getStepSize();
62 if (stepSize <= 0) {
63 log.warn("Invalid stepSize: {}. Positive number is required for the stepSize. Fallback to stepSize: 1", stepSize);
64 stepSize = 1;
65 }
66 this.definition = definition;
67 sliderValueLabel = new Label("");
68 int decimalDigits = digitsAfterDecimalPoint(stepSize);
69 this.slider = new Slider(definition.getMin(), definition.getMax(), decimalDigits + 1);
70 this.slider.setCaption(definition.getLabel());
71 slider.addValueChangeListener(createStepValueChangeListener(stepSize, decimalDigits));
72 }
73
74 @Override
75 protected Component initContent() {
76 addStyleName("sliderfield");
77 HorizontalLayout rootLayout = new HorizontalLayout();
78 rootLayout.setSizeFull();
79 rootLayout.setSpacing(false);
80 sliderValueLabel.addStyleName("slider-value");
81 sliderValueLabel.setWidth("50px");
82 rootLayout.addComponent(sliderValueLabel);
83 VerticalLayout sliderWithGridLayout = new VerticalLayout();
84 sliderWithGridLayout.setSizeFull();
85 sliderWithGridLayout.setSpacing(false);
86 slider.setWidth("100%");
87 sliderWithGridLayout.addComponent(slider);
88 sliderWithGridLayout.setExpandRatio(slider, 1);
89 if (definition.getGridStepSize() > 0) {
90 sliderWithGridLayout.addComponent(createGrid());
91 }
92 rootLayout.addComponent(sliderWithGridLayout);
93 rootLayout.setExpandRatio(sliderWithGridLayout, 1f);
94 return rootLayout;
95 }
96
97 @Override
98 protected void doSetValue(Double value) {
99 slider.setValue(value == null ? 0.0 : value);
100 }
101
102 @Override
103 public Double getValue() {
104 return slider.getValue();
105 }
106
107 @Override
108 public Registration addValueChangeListener(ValueChangeListener<Double> listener) {
109 return slider.addValueChangeListener(listener);
110 }
111
112 private int digitsAfterDecimalPoint(double value) {
113 String stringValue = Double.toString(value);
114 int decimalIndex = stringValue.indexOf('.');
115 int digitsAfterDecimalPoint = stringValue.length() - decimalIndex - 1;
116 char lastDecimalDigit = stringValue.charAt(stringValue.length() - 1);
117 return lastDecimalDigit == '0' ? digitsAfterDecimalPoint - 1 : digitsAfterDecimalPoint;
118 }
119
120 private HasValue.ValueChangeListener<Double> createStepValueChangeListener(double stepSize, int decimalDigits) {
121 return valueChangeEvent -> {
122 int toIntMultiplier = (int) Math.pow(10, slider.getResolution());
123 int intStepSize = (int) (stepSize * toIntMultiplier);
124 int sliderIntValue = (int) (valueChangeEvent.getValue() * toIntMultiplier);
125 if (sliderIntValue % intStepSize == 0) {
126 sliderValueLabel.setValue(definition.getValueFormat().apply(valueChangeEvent.getValue(), decimalDigits));
127 return;
128 }
129 if (valueChangeEvent.getValue() > valueChangeEvent.getOldValue()) {
130
131 slider.setValue((double) ((sliderIntValue / intStepSize + 1) * intStepSize) / toIntMultiplier);
132 } else {
133
134 slider.setValue((double) ((sliderIntValue / intStepSize) * intStepSize) / toIntMultiplier);
135 }
136 };
137 }
138
139 private Layout createGrid() {
140 HorizontalLayout gridLayout = new HorizontalLayout();
141 gridLayout.setSpacing(false);
142 gridLayout.setWidth("100%");
143 gridLayout.setHeight("5px");
144 gridLayout.setMargin(new MarginInfo(false, true));
145 gridLayout.addStyleName("slidergrid");
146 double gridStepSize = definition.getGridStepSize();
147 int gridSize = (int) ((definition.getMax() - definition.getMin()) / gridStepSize);
148 float gridExpansionRatio = 1f / (float) gridSize;
149 int decimalDigits = digitsAfterDecimalPoint(gridStepSize);
150 for (int gridIndex = 0; gridIndex < gridSize; gridIndex++) {
151 double gridValue = definition.getMin() + gridIndex * gridStepSize;
152 Label gridLabel = new Label(definition.getValueFormat().apply(gridValue, decimalDigits));
153 gridLayout.addComponent(gridLabel);
154 gridLayout.setExpandRatio(gridLabel, gridExpansionRatio);
155 }
156 Label lastGridLabel = new Label(definition.getValueFormat().apply(definition.getMax(), decimalDigits));
157 gridLayout.addComponent(lastGridLabel);
158 return gridLayout;
159 }
160 }