6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.javafx.scene.control.skin;
27
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.List;
31
32 import com.sun.javafx.scene.control.behavior.BehaviorBase;
33 import javafx.animation.Animation;
34 import javafx.animation.KeyFrame;
35 import javafx.animation.KeyValue;
36 import javafx.animation.Timeline;
37 import javafx.beans.InvalidationListener;
38 import javafx.beans.property.BooleanProperty;
39 import javafx.beans.property.IntegerProperty;
40 import javafx.beans.property.ObjectProperty;
41 import javafx.beans.value.WritableValue;
42 import javafx.collections.FXCollections;
43 import javafx.collections.ObservableList;
44 import javafx.geometry.NodeOrientation;
45 import javafx.geometry.VPos;
46 import javafx.scene.Node;
47 import javafx.scene.control.ProgressIndicator;
48 import javafx.scene.control.SkinBase;
49 import javafx.scene.layout.Pane;
50 import javafx.scene.layout.Region;
51 import javafx.scene.layout.StackPane;
52 import javafx.scene.paint.Color;
53 import javafx.scene.paint.Paint;
54 import javafx.scene.shape.Arc;
55 import javafx.scene.shape.ArcType;
56 import javafx.scene.shape.Circle;
57 import javafx.scene.text.Text;
58 import javafx.scene.transform.Scale;
59 import javafx.util.Duration;
60 import javafx.css.CssMetaData;
61 import javafx.css.StyleableObjectProperty;
62 import javafx.css.StyleableProperty;
63 import javafx.css.StyleableBooleanProperty;
64 import javafx.css.StyleableIntegerProperty;
65 import com.sun.javafx.css.converters.BooleanConverter;
66 import com.sun.javafx.css.converters.PaintConverter;
67 import com.sun.javafx.css.converters.SizeConverter;
68 import com.sun.javafx.scene.control.skin.resources.ControlResources;
69 import javafx.css.Styleable;
70
71 public class ProgressIndicatorSkin extends BehaviorSkinBase<ProgressIndicator, BehaviorBase<ProgressIndicator>> {
72
73 /***************************************************************************
74 * *
75 * CSS properties *
76 * *
77 **************************************************************************/
78
79 /**
80 * The colour of the progress segment.
81 */
82 private ObjectProperty<Paint> progressColor = new StyleableObjectProperty<Paint>(null) {
83 @Override protected void invalidated() {
84 final Paint value = get();
85 if (value != null && !(value instanceof Color)) {
86 if (isBound()) {
87 unbind();
88 }
89 set(null);
90 throw new IllegalArgumentException("Only Color objects are supported");
91 }
92 if (spinner!=null) spinner.setFillOverride(value);
93 if (determinateIndicator!=null) determinateIndicator.setFillOverride(value);
94 }
95
139 if (spinner!=null) spinner.setSpinEnabled(get());
140 }
141
142 @Override public CssMetaData<ProgressIndicator,Boolean> getCssMetaData() {
143 return SPIN_ENABLED;
144 }
145
146 @Override public Object getBean() {
147 return ProgressIndicatorSkin.this;
148 }
149
150 @Override public String getName() {
151 return "spinEnabled";
152 }
153 };
154
155
156
157 /***************************************************************************
158 * *
159 * Private fields *
160 * *
161 **************************************************************************/
162
163 private static final String DONE = ControlResources.getString("ProgressIndicator.doneString");
164
165 /** doneText is just used to know the size of done as that is the biggest text we need to allow for */
166 private static final Text doneText = new Text(DONE);
167 static {
168 doneText.getStyleClass().add("text");
169 }
170
171 private IndeterminateSpinner spinner;
172 private DeterminateIndicator determinateIndicator;
173 private ProgressIndicator control;
174
175 protected Animation indeterminateTransition;
176
177
178
179 /***************************************************************************
180 * *
181 * Constructors *
182 * *
183 **************************************************************************/
184
185 public ProgressIndicatorSkin(ProgressIndicator control) {
186 super(control, new BehaviorBase<ProgressIndicator>(control, Collections.emptyList()));
187
188 this.control = control;
189
190 // register listeners
191 registerChangeListener(control.indeterminateProperty(), "INDETERMINATE");
192 registerChangeListener(control.progressProperty(), "PROGRESS");
193 registerChangeListener(control.visibleProperty(), "VISIBLE");
194 registerChangeListener(control.parentProperty(), "PARENT");
195 registerChangeListener(control.sceneProperty(), "SCENE");
196
197 initialize();
198 }
199
200
201 /***************************************************************************
202 * *
203 * API (for ProgressBarSkin) *
204 * *
205 **************************************************************************/
206
207 @Override protected void handleControlPropertyChanged(String p) {
208 super.handleControlPropertyChanged(p);
209
210 if ("INDETERMINATE".equals(p)) {
211 initialize();
212 } else if ("PROGRESS".equals(p)) {
213 updateProgress();
214 } else if ("VISIBLE".equals(p)) {
215 updateAnimation();
216 } else if ("PARENT".equals(p)) {
217 updateAnimation();
218 } else if ("SCENE".equals(p)) {
219 updateAnimation();
220 }
221 }
222
223 protected void initialize() {
224 boolean isIndeterminate = control.isIndeterminate();
225 if (isIndeterminate) {
226 // clean up determinateIndicator
227 determinateIndicator = null;
228
229 // create spinner
230 spinner = new IndeterminateSpinner(spinEnabled.get(), progressColor.get());
231 getChildren().setAll(spinner);
232 if (control.impl_isTreeVisible()) {
233 if (indeterminateTransition != null) {
234 indeterminateTransition.play();
235 }
236 }
237 } else {
238 // clean up after spinner
239 if (spinner != null) {
240 if (indeterminateTransition != null) {
241 indeterminateTransition.stop();
242 }
243 spinner = null;
244 }
245
246 // create determinateIndicator
247 determinateIndicator = new DeterminateIndicator(control, this, progressColor.get());
248 getChildren().setAll(determinateIndicator);
249 }
250 }
251
252 @Override public void dispose() {
253 super.dispose();
254
255 if (indeterminateTransition != null) {
256 indeterminateTransition.stop();
257 indeterminateTransition = null;
258 }
259
260 if (spinner != null) {
261 spinner = null;
262 }
263
264 control = null;
265 }
266
267 protected void updateProgress() {
268 if (determinateIndicator != null) {
269 determinateIndicator.updateProgress(control.getProgress());
270 }
271 }
272
273 protected void createIndeterminateTimeline() {
274 if (spinner != null) {
275 spinner.rebuildTimeline();
276 }
277 }
278
279 protected void pauseTimeline(boolean pause) {
280 if (getSkinnable().isIndeterminate()) {
281 if (indeterminateTransition == null) {
282 createIndeterminateTimeline();
283 }
284 if (pause) {
285 indeterminateTransition.pause();
286 } else {
287 indeterminateTransition.play();
288 }
289 }
290 }
291
292 protected void updateAnimation() {
293 ProgressIndicator control = getSkinnable();
294 final boolean isTreeVisible = control.isVisible() &&
295 control.getParent() != null &&
296 control.getScene() != null;
297 if (indeterminateTransition != null) {
298 pauseTimeline(! isTreeVisible);
299 } else if (isTreeVisible) {
300 createIndeterminateTimeline();
301 }
302 }
303
304
305
306 /***************************************************************************
307 * *
308 * Listeners *
309 * *
310 **************************************************************************/
311
312
313
314
315 /***************************************************************************
316 * *
317 * Layout *
318 * *
319 **************************************************************************/
320
321 @Override protected void layoutChildren(final double x, final double y,
322 final double w, final double h) {
323 if (spinner != null && control.isIndeterminate()) {
324 spinner.layoutChildren();
325 spinner.resizeRelocate(0, 0, w, h);
326 } else if (determinateIndicator != null) {
327 determinateIndicator.layoutChildren();
328 determinateIndicator.resizeRelocate(0, 0, w, h);
329 }
330 }
331
332
333
334 /***************************************************************************
335 * *
336 * DeterminateIndicator *
337 * *
338 **************************************************************************/
339
340 private class DeterminateIndicator extends Region {
341 private double textGap = 2.0F;
342
343 // only update progress text on whole percentages
344 private int intProgress;
345
346 // only update pie arc to nearest degree
347 private int degProgress;
348 private Text text;
349 private StackPane indicator;
350 private StackPane progress;
351 private StackPane tick;
352 private Arc arcShape;
353 private Circle indicatorCircle;
354
355 public DeterminateIndicator(ProgressIndicator control, ProgressIndicatorSkin s, Paint fillOverride) {
356
357 getStyleClass().add("determinate-indicator");
358
359 intProgress = (int) Math.round(control.getProgress() * 100.0) ;
360 degProgress = (int) (360 * control.getProgress());
518 final double pRight = progress.snappedRightInset();
519 final double pTop = progress.snappedTopInset();
520 final double pBottom = progress.snappedBottomInset();
521 final double progressMax = snapSize(Math.max(Math.max(pLeft, pRight), Math.max(pTop, pBottom)));
522 final double tTop = tick.snappedTopInset();
523 final double tBottom = tick.snappedBottomInset();
524 final double indicatorHeight = indicatorMax + progressMax + tTop + tBottom + progressMax + indicatorMax;
525 return top + indicatorHeight + textGap + doneText.getLayoutBounds().getHeight() + bottom;
526 }
527
528 @Override protected double computeMaxWidth(double height) {
529 return computePrefWidth(height);
530 }
531
532 @Override protected double computeMaxHeight(double width) {
533 return computePrefHeight(width);
534 }
535 }
536
537
538
539 /***************************************************************************
540 * *
541 * IndeterminateSpinner *
542 * *
543 **************************************************************************/
544
545 protected final Duration CLIPPED_DELAY = new Duration(300);
546 protected final Duration UNCLIPPED_DELAY = new Duration(0);
547
548 private final class IndeterminateSpinner extends Region {
549 private IndicatorPaths pathsG;
550 private final List<Double> opacities = new ArrayList<>();
551 private boolean spinEnabled = false;
552 private Paint fillOverride = null;
553
554 private IndeterminateSpinner(boolean spinEnabled, Paint fillOverride) {
555 this.spinEnabled = spinEnabled;
556 this.fillOverride = fillOverride;
557
558 setNodeOrientation(NodeOrientation.LEFT_TO_RIGHT);
559 getStyleClass().setAll("spinner");
560
561 pathsG = new IndicatorPaths();
562 getChildren().add(pathsG);
563 rebuild();
564
565 rebuildTimeline();
566
567 }
685 region.getStyleClass().addAll("segment", "segment" + i);
686 if (fillOverride instanceof Color) {
687 Color c = (Color)fillOverride;
688 region.setStyle("-fx-background-color: rgba("+((int)(255*c.getRed()))+","+((int)(255*c.getGreen()))+","+((int)(255*c.getBlue()))+","+c.getOpacity()+");");
689 } else {
690 region.setStyle(null);
691 }
692 pathsG.getChildren().add(region);
693 opacities.add(Math.max(0.1, (1.0 - (step*i))));
694 }
695 }
696
697 private void shiftColors() {
698 if (opacities.size() <= 0) return;
699 final int segments = indeterminateSegmentCount.get();
700 Collections.rotate(opacities, -1);
701 for (int i = 0; i < segments; i++) {
702 pathsG.getChildren().get(i).setOpacity(opacities.get(i));
703 }
704 }
705 }
706
707
708
709 /***************************************************************************
710 * *
711 * Stylesheet Handling *
712 * *
713 **************************************************************************/
714
715 private static final CssMetaData<ProgressIndicator,Paint> PROGRESS_COLOR =
716 new CssMetaData<ProgressIndicator,Paint>("-fx-progress-color",
717 PaintConverter.getInstance(), null) {
718
719 @Override
720 public boolean isSettable(ProgressIndicator n) {
721 final ProgressIndicatorSkin skin = (ProgressIndicatorSkin) n.getSkin();
722 return skin.progressColor == null ||
723 !skin.progressColor.isBound();
724 }
725
726 @Override
727 public StyleableProperty<Paint> getStyleableProperty(ProgressIndicator n) {
728 final ProgressIndicatorSkin skin = (ProgressIndicatorSkin) n.getSkin();
729 return (StyleableProperty<Paint>)(WritableValue<Paint>)skin.progressColor;
730 }
731 };
732 private static final CssMetaData<ProgressIndicator,Number> INDETERMINATE_SEGMENT_COUNT =
733 new CssMetaData<ProgressIndicator,Number>("-fx-indeterminate-segment-count",
734 SizeConverter.getInstance(), 8) {
735
736 @Override public boolean isSettable(ProgressIndicator n) {
737 final ProgressIndicatorSkin skin = (ProgressIndicatorSkin) n.getSkin();
738 return skin.indeterminateSegmentCount == null ||
739 !skin.indeterminateSegmentCount.isBound();
740 }
741
742 @Override public StyleableProperty<Number> getStyleableProperty(ProgressIndicator n) {
743 final ProgressIndicatorSkin skin = (ProgressIndicatorSkin) n.getSkin();
744 return (StyleableProperty<Number>)(WritableValue<Number>)skin.indeterminateSegmentCount;
745 }
746 };
747 private static final CssMetaData<ProgressIndicator,Boolean> SPIN_ENABLED =
748 new CssMetaData<ProgressIndicator,Boolean>("-fx-spin-enabled", BooleanConverter.getInstance(), Boolean.FALSE) {
749
750 @Override public boolean isSettable(ProgressIndicator node) {
751 final ProgressIndicatorSkin skin = (ProgressIndicatorSkin) node.getSkin();
752 return skin.spinEnabled == null || !skin.spinEnabled.isBound();
753 }
754
755 @Override public StyleableProperty<Boolean> getStyleableProperty(ProgressIndicator node) {
756 final ProgressIndicatorSkin skin = (ProgressIndicatorSkin) node.getSkin();
757 return (StyleableProperty<Boolean>)(WritableValue<Boolean>)skin.spinEnabled;
758 }
759 };
760
761 public static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
762 static {
763 final List<CssMetaData<? extends Styleable, ?>> styleables =
764 new ArrayList<CssMetaData<? extends Styleable, ?>>(SkinBase.getClassCssMetaData());
765 styleables.add(PROGRESS_COLOR);
766 styleables.add(INDETERMINATE_SEGMENT_COUNT);
767 styleables.add(SPIN_ENABLED);
768 STYLEABLES = Collections.unmodifiableList(styleables);
769 }
770
771 /**
772 * @return The CssMetaData associated with this class, which may include the
773 * CssMetaData of its super classes.
774 */
775 public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
776 return STYLEABLES;
777 }
778
779 /**
780 * {@inheritDoc}
781 */
782 @Override
783 public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
784 return getClassCssMetaData();
785 }
786 }
|
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javafx.scene.control.skin;
27
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.List;
31
32 import javafx.animation.Animation;
33 import javafx.animation.KeyFrame;
34 import javafx.animation.KeyValue;
35 import javafx.animation.Timeline;
36 import javafx.beans.property.BooleanProperty;
37 import javafx.beans.property.IntegerProperty;
38 import javafx.beans.property.ObjectProperty;
39 import javafx.beans.value.WritableValue;
40 import javafx.collections.FXCollections;
41 import javafx.collections.ObservableList;
42 import javafx.geometry.NodeOrientation;
43 import javafx.geometry.VPos;
44 import javafx.scene.Node;
45 import javafx.scene.control.Control;
46 import javafx.scene.control.ProgressIndicator;
47 import javafx.scene.control.SkinBase;
48 import javafx.scene.layout.Pane;
49 import javafx.scene.layout.Region;
50 import javafx.scene.layout.StackPane;
51 import javafx.scene.paint.Color;
52 import javafx.scene.paint.Paint;
53 import javafx.scene.shape.Arc;
54 import javafx.scene.shape.ArcType;
55 import javafx.scene.shape.Circle;
56 import javafx.scene.text.Text;
57 import javafx.scene.transform.Scale;
58 import javafx.util.Duration;
59 import javafx.css.CssMetaData;
60 import javafx.css.StyleableObjectProperty;
61 import javafx.css.StyleableProperty;
62 import javafx.css.StyleableBooleanProperty;
63 import javafx.css.StyleableIntegerProperty;
64 import javafx.css.converter.BooleanConverter;
65 import javafx.css.converter.PaintConverter;
66 import javafx.css.converter.SizeConverter;
67 import com.sun.javafx.scene.control.skin.resources.ControlResources;
68 import javafx.css.Styleable;
69
70 /**
71 * Default skin implementation for the {@link ProgressIndicator} control.
72 *
73 * @see ProgressIndicator
74 * @since 9
75 */
76 public class ProgressIndicatorSkin extends SkinBase<ProgressIndicator> {
77
78 /***************************************************************************
79 * *
80 * Static fields *
81 * *
82 **************************************************************************/
83
84 private static final String DONE = ControlResources.getString("ProgressIndicator.doneString");
85
86 /** doneText is just used to know the size of done as that is the biggest text we need to allow for */
87 private static final Text doneText = new Text(DONE);
88 static {
89 doneText.getStyleClass().add("text");
90 }
91
92
93
94 /***************************************************************************
95 * *
96 * Private fields *
97 * *
98 **************************************************************************/
99
100 final Duration CLIPPED_DELAY = new Duration(300);
101 final Duration UNCLIPPED_DELAY = new Duration(0);
102
103 private IndeterminateSpinner spinner;
104 private DeterminateIndicator determinateIndicator;
105 private ProgressIndicator control;
106
107 Animation indeterminateTransition;
108
109
110
111 /***************************************************************************
112 * *
113 * Constructors *
114 * *
115 **************************************************************************/
116
117 /**
118 * Creates a new ProgressIndicatorSkin instance, installing the necessary child
119 * nodes into the Control {@link Control#getChildren() children} list, as
120 * well as the necessary {@link Node#getInputMap() input mappings} for
121 * handling key, mouse, etc events.
122 *
123 * @param control The control that this skin should be installed onto.
124 */
125 public ProgressIndicatorSkin(ProgressIndicator control) {
126 super(control);
127
128 this.control = control;
129
130 // register listeners
131 registerChangeListener(control.indeterminateProperty(), e -> initialize());
132 registerChangeListener(control.progressProperty(), e -> updateProgress());
133 registerChangeListener(control.visibleProperty(), e -> updateAnimation());
134 registerChangeListener(control.parentProperty(), e -> updateAnimation());
135 registerChangeListener(control.sceneProperty(), e -> updateAnimation());
136
137 initialize();
138 }
139
140
141
142 /***************************************************************************
143 * *
144 * Properties *
145 * *
146 **************************************************************************/
147
148 /**
149 * The colour of the progress segment.
150 */
151 private ObjectProperty<Paint> progressColor = new StyleableObjectProperty<Paint>(null) {
152 @Override protected void invalidated() {
153 final Paint value = get();
154 if (value != null && !(value instanceof Color)) {
155 if (isBound()) {
156 unbind();
157 }
158 set(null);
159 throw new IllegalArgumentException("Only Color objects are supported");
160 }
161 if (spinner!=null) spinner.setFillOverride(value);
162 if (determinateIndicator!=null) determinateIndicator.setFillOverride(value);
163 }
164
208 if (spinner!=null) spinner.setSpinEnabled(get());
209 }
210
211 @Override public CssMetaData<ProgressIndicator,Boolean> getCssMetaData() {
212 return SPIN_ENABLED;
213 }
214
215 @Override public Object getBean() {
216 return ProgressIndicatorSkin.this;
217 }
218
219 @Override public String getName() {
220 return "spinEnabled";
221 }
222 };
223
224
225
226 /***************************************************************************
227 * *
228 * Public API *
229 * *
230 **************************************************************************/
231
232 /** {@inheritDoc} */
233 @Override public void dispose() {
234 super.dispose();
235
236 if (indeterminateTransition != null) {
237 indeterminateTransition.stop();
238 indeterminateTransition = null;
239 }
240
241 if (spinner != null) {
242 spinner = null;
243 }
244
245 control = null;
246 }
247
248 /** {@inheritDoc} */
249 @Override protected void layoutChildren(final double x, final double y,
250 final double w, final double h) {
251 if (spinner != null && control.isIndeterminate()) {
252 spinner.layoutChildren();
253 spinner.resizeRelocate(0, 0, w, h);
254 } else if (determinateIndicator != null) {
255 determinateIndicator.layoutChildren();
256 determinateIndicator.resizeRelocate(0, 0, w, h);
257 }
258 }
259
260
261
262 /***************************************************************************
263 * *
264 * Private implementation *
265 * *
266 **************************************************************************/
267
268 void initialize() {
269 boolean isIndeterminate = control.isIndeterminate();
270 if (isIndeterminate) {
271 // clean up determinateIndicator
272 determinateIndicator = null;
273
274 // create spinner
275 spinner = new IndeterminateSpinner(spinEnabled.get(), progressColor.get());
276 getChildren().setAll(spinner);
277 if (control.impl_isTreeVisible()) {
278 if (indeterminateTransition != null) {
279 indeterminateTransition.play();
280 }
281 }
282 } else {
283 // clean up after spinner
284 if (spinner != null) {
285 if (indeterminateTransition != null) {
286 indeterminateTransition.stop();
287 }
288 spinner = null;
289 }
290
291 // create determinateIndicator
292 determinateIndicator = new DeterminateIndicator(control, this, progressColor.get());
293 getChildren().setAll(determinateIndicator);
294 }
295 }
296
297 void updateProgress() {
298 if (determinateIndicator != null) {
299 determinateIndicator.updateProgress(control.getProgress());
300 }
301 }
302
303 void createIndeterminateTimeline() {
304 if (spinner != null) {
305 spinner.rebuildTimeline();
306 }
307 }
308
309 void pauseTimeline(boolean pause) {
310 if (getSkinnable().isIndeterminate()) {
311 if (indeterminateTransition == null) {
312 createIndeterminateTimeline();
313 }
314 if (pause) {
315 indeterminateTransition.pause();
316 } else {
317 indeterminateTransition.play();
318 }
319 }
320 }
321
322 void updateAnimation() {
323 ProgressIndicator control = getSkinnable();
324 final boolean isTreeVisible = control.isVisible() &&
325 control.getParent() != null &&
326 control.getScene() != null;
327 if (indeterminateTransition != null) {
328 pauseTimeline(!isTreeVisible);
329 } else if (isTreeVisible) {
330 createIndeterminateTimeline();
331 }
332 }
333
334
335
336 /***************************************************************************
337 * *
338 * Stylesheet Handling *
339 * *
340 **************************************************************************/
341
342 private static final CssMetaData<ProgressIndicator,Paint> PROGRESS_COLOR =
343 new CssMetaData<ProgressIndicator,Paint>("-fx-progress-color",
344 PaintConverter.getInstance(), null) {
345
346 @Override
347 public boolean isSettable(ProgressIndicator n) {
348 final ProgressIndicatorSkin skin = (ProgressIndicatorSkin) n.getSkin();
349 return skin.progressColor == null ||
350 !skin.progressColor.isBound();
351 }
352
353 @Override
354 public StyleableProperty<Paint> getStyleableProperty(ProgressIndicator n) {
355 final ProgressIndicatorSkin skin = (ProgressIndicatorSkin) n.getSkin();
356 return (StyleableProperty<Paint>)(WritableValue<Paint>)skin.progressColor;
357 }
358 };
359 private static final CssMetaData<ProgressIndicator,Number> INDETERMINATE_SEGMENT_COUNT =
360 new CssMetaData<ProgressIndicator,Number>("-fx-indeterminate-segment-count",
361 SizeConverter.getInstance(), 8) {
362
363 @Override public boolean isSettable(ProgressIndicator n) {
364 final ProgressIndicatorSkin skin = (ProgressIndicatorSkin) n.getSkin();
365 return skin.indeterminateSegmentCount == null ||
366 !skin.indeterminateSegmentCount.isBound();
367 }
368
369 @Override public StyleableProperty<Number> getStyleableProperty(ProgressIndicator n) {
370 final ProgressIndicatorSkin skin = (ProgressIndicatorSkin) n.getSkin();
371 return (StyleableProperty<Number>)(WritableValue<Number>)skin.indeterminateSegmentCount;
372 }
373 };
374 private static final CssMetaData<ProgressIndicator,Boolean> SPIN_ENABLED =
375 new CssMetaData<ProgressIndicator,Boolean>("-fx-spin-enabled", BooleanConverter.getInstance(), Boolean.FALSE) {
376
377 @Override public boolean isSettable(ProgressIndicator node) {
378 final ProgressIndicatorSkin skin = (ProgressIndicatorSkin) node.getSkin();
379 return skin.spinEnabled == null || !skin.spinEnabled.isBound();
380 }
381
382 @Override public StyleableProperty<Boolean> getStyleableProperty(ProgressIndicator node) {
383 final ProgressIndicatorSkin skin = (ProgressIndicatorSkin) node.getSkin();
384 return (StyleableProperty<Boolean>)(WritableValue<Boolean>)skin.spinEnabled;
385 }
386 };
387
388 private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
389 static {
390 final List<CssMetaData<? extends Styleable, ?>> styleables =
391 new ArrayList<CssMetaData<? extends Styleable, ?>>(SkinBase.getClassCssMetaData());
392 styleables.add(PROGRESS_COLOR);
393 styleables.add(INDETERMINATE_SEGMENT_COUNT);
394 styleables.add(SPIN_ENABLED);
395 STYLEABLES = Collections.unmodifiableList(styleables);
396 }
397
398 /**
399 * Returns the CssMetaData associated with this class, which may include the
400 * CssMetaData of its super classes.
401 */
402 public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
403 return STYLEABLES;
404 }
405
406 /**
407 * {@inheritDoc}
408 */
409 @Override
410 public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
411 return getClassCssMetaData();
412 }
413
414
415
416 /***************************************************************************
417 * *
418 * Support classes *
419 * *
420 **************************************************************************/
421
422 private final class DeterminateIndicator extends Region {
423 private double textGap = 2.0F;
424
425 // only update progress text on whole percentages
426 private int intProgress;
427
428 // only update pie arc to nearest degree
429 private int degProgress;
430 private Text text;
431 private StackPane indicator;
432 private StackPane progress;
433 private StackPane tick;
434 private Arc arcShape;
435 private Circle indicatorCircle;
436
437 public DeterminateIndicator(ProgressIndicator control, ProgressIndicatorSkin s, Paint fillOverride) {
438
439 getStyleClass().add("determinate-indicator");
440
441 intProgress = (int) Math.round(control.getProgress() * 100.0) ;
442 degProgress = (int) (360 * control.getProgress());
600 final double pRight = progress.snappedRightInset();
601 final double pTop = progress.snappedTopInset();
602 final double pBottom = progress.snappedBottomInset();
603 final double progressMax = snapSize(Math.max(Math.max(pLeft, pRight), Math.max(pTop, pBottom)));
604 final double tTop = tick.snappedTopInset();
605 final double tBottom = tick.snappedBottomInset();
606 final double indicatorHeight = indicatorMax + progressMax + tTop + tBottom + progressMax + indicatorMax;
607 return top + indicatorHeight + textGap + doneText.getLayoutBounds().getHeight() + bottom;
608 }
609
610 @Override protected double computeMaxWidth(double height) {
611 return computePrefWidth(height);
612 }
613
614 @Override protected double computeMaxHeight(double width) {
615 return computePrefHeight(width);
616 }
617 }
618
619
620 private final class IndeterminateSpinner extends Region {
621 private IndicatorPaths pathsG;
622 private final List<Double> opacities = new ArrayList<>();
623 private boolean spinEnabled = false;
624 private Paint fillOverride = null;
625
626 private IndeterminateSpinner(boolean spinEnabled, Paint fillOverride) {
627 this.spinEnabled = spinEnabled;
628 this.fillOverride = fillOverride;
629
630 setNodeOrientation(NodeOrientation.LEFT_TO_RIGHT);
631 getStyleClass().setAll("spinner");
632
633 pathsG = new IndicatorPaths();
634 getChildren().add(pathsG);
635 rebuild();
636
637 rebuildTimeline();
638
639 }
757 region.getStyleClass().addAll("segment", "segment" + i);
758 if (fillOverride instanceof Color) {
759 Color c = (Color)fillOverride;
760 region.setStyle("-fx-background-color: rgba("+((int)(255*c.getRed()))+","+((int)(255*c.getGreen()))+","+((int)(255*c.getBlue()))+","+c.getOpacity()+");");
761 } else {
762 region.setStyle(null);
763 }
764 pathsG.getChildren().add(region);
765 opacities.add(Math.max(0.1, (1.0 - (step*i))));
766 }
767 }
768
769 private void shiftColors() {
770 if (opacities.size() <= 0) return;
771 final int segments = indeterminateSegmentCount.get();
772 Collections.rotate(opacities, -1);
773 for (int i = 0; i < segments; i++) {
774 pathsG.getChildren().get(i).setOpacity(opacities.get(i));
775 }
776 }
777 }
778 }
|