From b436117928ce7551889f86f9f816e061a28ed098 Mon Sep 17 00:00:00 2001 From: fmittag Date: Thu, 2 Feb 2012 17:00:28 +0100 Subject: [PATCH] fix some bugs of timepanel/sliderbar --- .../gwt/ui/adminconsole/RaceMapPanel.java | 35 +- .../gwt/ui/adminconsole/RaceMapResources.java | 6 +- .../sap/sailing/gwt/ui/client/TimePanel.java | 45 +- .../com/sap/sailing/gwt/ui/client/Timer.java | 28 +- .../gwt/ui/raceboard/RaceBoardEntryPoint.java | 138 +- .../gwt/ui/raceboard/RaceBoardPanel.java | 23 +- .../gwt/ui/shared/controls/SliderBar.java | 2111 ++++++++--------- 7 files changed, 1231 insertions(+), 1155 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceMapPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceMapPanel.java index c6f6039aa0b..5afce98ed74 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceMapPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceMapPanel.java @@ -124,22 +124,36 @@ public class RaceMapPanel extends FormPanel implements EventDisplayer, TimeListe RaceIdentifier raceIdentifier = selectedRaces.get(selectedRaces.size() - 1); RaceDTO race = raceListBox.getRace(raceIdentifier); competitorSelectionProvider.setCompetitors(race.competitors); - updateSlider(race); - if (race.startOfRace != null) { - timePanel.timeChanged(race.startOfRace); - timer.setTime(race.startOfRace.getTime()); - } + + updateTimePanel(race); } raceMap.onRaceSelectionChange(selectedRaces); } - private void updateSlider(RaceDTO selectedRace) { + private void updateTimePanel(RaceDTO selectedRace) { + Date min = null; + Date max = null; + if (selectedRace.startOfTracking != null) { - timePanel.setMin(selectedRace.startOfTracking); + min = selectedRace.startOfTracking; } - if (selectedRace.timePointOfNewestEvent != null) { - timePanel.setMax(selectedRace.timePointOfNewestEvent); + if (selectedRace.endOfRace != null) { + max = selectedRace.endOfRace; + } else if (selectedRace.timePointOfNewestEvent != null) { + max = selectedRace.timePointOfNewestEvent; } + + if(min != null && max != null) + timePanel.setMinMax(min, max); + + // set initial timer position + switch(timer.getPlayMode()) { + case Live: + case Replay: + timer.setTime(selectedRace.startOfRace.getTime()); + break; + } + timePanel.setLegMarkers(); } @Override @@ -182,5 +196,8 @@ public class RaceMapPanel extends FormPanel implements EventDisplayer, TimeListe if (raceMap.map != null) { raceMap.map.onResize(); } + if (timePanel != null) { + timePanel.onResize(); + } } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceMapResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceMapResources.java index 227f12eebcd..f473109d0bb 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceMapResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/RaceMapResources.java @@ -191,7 +191,9 @@ public class RaceMapResources { // here it would be better to get the boat length from the boat class -> for now we assume a length of 5m double boatLengthInMeter = 5.0; if (zoomLevel > 5) { - int boatSizeXInPixel = imageSize.getWidth(); + int boatLengthInPixel = imageSize.getHeight(); + if(imageSize.getWidth() > boatLengthInPixel) + boatLengthInPixel = imageSize.getWidth(); LatLngBounds bounds = map.getBounds(); if (bounds != null) { LatLng upperRight = bounds.getNorthEast(); @@ -200,7 +202,7 @@ public class RaceMapResources { double distXInMeters = upperLeft.distanceFrom(upperRight); int widthInPixel = map.getSize().getWidth(); double realBoatSizeInPixel = (widthInPixel * boatLengthInMeter) / distXInMeters; - realBoatSizeScaleFactor = realBoatSizeInPixel / (double) boatSizeXInPixel; + realBoatSizeScaleFactor = realBoatSizeInPixel / (double) boatLengthInPixel; if (realBoatSizeScaleFactor < minScaleFactor) { realBoatSizeScaleFactor = minScaleFactor; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/TimePanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/TimePanel.java index f5bbad2a95d..363bc4ea176 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/TimePanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/TimePanel.java @@ -19,6 +19,7 @@ import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.IntegerBox; import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.RequiresResize; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.gwt.ui.client.Timer.PlayModes; @@ -27,7 +28,7 @@ import com.sap.sailing.gwt.ui.shared.components.SettingsDialog; import com.sap.sailing.gwt.ui.shared.components.SettingsDialogComponent; import com.sap.sailing.gwt.ui.shared.controls.SliderBar; -public class TimePanel extends FormPanel implements Component, TimeListener, PlayStateListener { +public class TimePanel extends FormPanel implements Component, TimeListener, PlayStateListener, RequiresResize { private final Timer timer; private final Button playPauseButton; private final IntegerBox playSpeedBox; @@ -67,9 +68,6 @@ public class TimePanel extends FormPanel implements Component sliderBar = new SliderBar(); sliderBar.setEnabled(true); - sliderBar.setStepSize(60000); - sliderBar.setNumTickLabels(8); - sliderBar.setNumTicks(8); sliderBar.setLabelFormatter(new SliderBar.LabelFormatter() { final DateTimeFormat formatter = DateTimeFormat.getFormat("HH:mm"); @Override @@ -224,7 +222,7 @@ public class TimePanel extends FormPanel implements Component switch(timer.getPlayMode()) { case Live: playModeLabel.setText(stringMessages.playModeLive()); - timeDelayLabel.setText(((int) timer.getDelay() / 1000) + " s"); + timeDelayLabel.setText(((int) timer.getCurrentDelay() / 1000) + " s"); break; case Replay: playModeLabel.setText(stringMessages.playModeReplay()); @@ -233,22 +231,34 @@ public class TimePanel extends FormPanel implements Component playModeLabel.setText(timer.getPlayMode().name()); } - public void setMin(Date min) { + public void setMinMax(Date min, Date max) { + int numTicks = 8; sliderBar.setMinValue(new Double(min.getTime())); - if (timer.getTime().before(min)) { - timer.setTime((long) min.getTime()); - } + sliderBar.setMaxValue(new Double(max.getTime())); + sliderBar.setNumTickLabels(numTicks); + sliderBar.setNumTicks(numTicks); + double stepSize = (max.getTime() - min.getTime()) / numTicks; + sliderBar.setStepSize(stepSize); } - public void setMax(Date max) { + public void changeMax(Date max) { sliderBar.setMaxValue(new Double(max.getTime())); if (timer.getTime().after(max)) { timer.setTime((long) max.getTime()); } } + public void changeMin(Date min) { + sliderBar.setMinValue(new Double(min.getTime())); + if (timer.getTime().before(min)) { + timer.setTime((long) min.getTime()); + } + } + public void setLegMarkers() { if(sliderBar.isMinMaxInitialized()) { + sliderBar.clearMarkers(); + Double minValue = sliderBar.getMinValue(); Double maxValue = sliderBar.getMaxValue(); int legCount = 5; @@ -256,7 +266,9 @@ public class TimePanel extends FormPanel implements Component double diff = (maxValue - minValue) / (double) legCount; for(int i = 0; i < legCount; i++) - sliderBar.addMarker("L" + i + 1, minValue + i * diff); + sliderBar.addMarker("L" + (i + 1), minValue + i * diff); + + sliderBar.redraw(); } } @@ -305,4 +317,15 @@ public class TimePanel extends FormPanel implements Component public String getLocalizedShortName() { return "Time control"; } + + @Override + public void onResize() { + // handle what is required by @link{ProvidesResize} + Widget child = getWidget(); + if (child instanceof RequiresResize) { + ((RequiresResize) child).onResize(); + } + + sliderBar.onResize(); + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/Timer.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/Timer.java index 28751e327b7..1a9398090c2 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/Timer.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/Timer.java @@ -20,6 +20,12 @@ public class Timer { */ private Date time; + /** + * The time delay to the current point in time in millisseconds + * will only be used in live play mode + */ + private long livePlayDelayInMs; + /** * Listeners interested in changes of {@link #time} */ @@ -80,6 +86,7 @@ public class Timer { playStateListeners = new HashSet(); playing = false; playSpeedFactor = 1.0; + livePlayDelayInMs = 0; this.delayBetweenAutoAdvancesInMilliseconds = delayBetweenAutoAdvancesInMilliseconds; this.playMode = playMode; } @@ -149,6 +156,10 @@ public class Timer { public void resume() { if (!playing) { playing = !playing; + + if(playMode == PlayModes.Live) + setTime(System.currentTimeMillis()-livePlayDelayInMs); + startAutoAdvance(); for (PlayStateListener playStateListener : playStateListeners) { playStateListener.playStateChanged(playing); @@ -179,20 +190,15 @@ public class Timer { Scheduler.get().scheduleFixedPeriod(command, (int) delayBetweenAutoAdvancesInMilliseconds); } - /** - * Indirect way of setting this timer to a specific point in time, namely to "now" - delayInMilliseconds. - */ public void setDelay(long delayInMilliseconds) { - if(playMode == PlayModes.Replay) - return; - - setTime(System.currentTimeMillis()-delayInMilliseconds); + this.livePlayDelayInMs = delayInMilliseconds; + } + + public long getDelay() { + return livePlayDelayInMs; } - public long getDelay() { - if(playMode == PlayModes.Replay) - return 0; - + public long getCurrentDelay() { return System.currentTimeMillis() - getTime().getTime(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java index d72cfa49415..7342cb69b83 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardEntryPoint.java @@ -4,15 +4,18 @@ import java.util.Collections; import java.util.List; import com.google.gwt.user.client.Window; -import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.RootPanel; import com.sap.sailing.domain.common.DefaultLeaderboardName; import com.sap.sailing.domain.common.RaceIdentifier; import com.sap.sailing.gwt.ui.client.AbstractEntryPoint; import com.sap.sailing.gwt.ui.client.LogoAndTitlePanel; +import com.sap.sailing.gwt.ui.client.ParallelExecutionCallback; +import com.sap.sailing.gwt.ui.client.ParallelExecutionHolder; import com.sap.sailing.gwt.ui.client.RaceSelectionModel; import com.sap.sailing.gwt.ui.shared.EventDTO; +import com.sap.sailing.gwt.ui.shared.LeaderboardDTO; +import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; import com.sap.sailing.gwt.ui.shared.RaceDTO; import com.sap.sailing.gwt.ui.shared.RegattaDTO; @@ -20,75 +23,100 @@ public class RaceBoardEntryPoint extends AbstractEntryPoint { private RaceDTO selectedRace; private RaceBoardPanel raceBoardPanel; + private String eventName; + private String raceName; + private String leaderboardName; + private String leaderboardGroupName; + @Override public void onModuleLoad() { super.onModuleLoad(); - - final String eventName = Window.Location.getParameter("eventName"); - final String raceName = Window.Location.getParameter("raceName"); + + eventName = Window.Location.getParameter("eventName"); + raceName = Window.Location.getParameter("raceName"); String leaderboardNameParamValue = Window.Location.getParameter("leaderboardName"); - //String leaderboardGroupNameParamValue = Window.Location.getParameter("leaderboardGroupName"); - final String leaderboardName; - //final String leaderboardGroupName; + String leaderboardGroupNameParamValue = Window.Location.getParameter("leaderboardGroupName"); + if(leaderboardNameParamValue == null || leaderboardNameParamValue.isEmpty()) { leaderboardName = DefaultLeaderboardName.DEFAULT_LEADERBOARD_NAME; } else { leaderboardName = leaderboardNameParamValue; - sailingService.getLeaderboardNames(new AsyncCallback>() { - @Override - public void onSuccess(List leaderboardNames) { - if (!leaderboardNames.contains(leaderboardName)) { - createErrorPage(stringMessages.noSuchLeaderboard()); - } - } - - @Override - public void onFailure(Throwable t) { - reportError("Error trying to obtain the list of leaderboard names: " + t.getMessage()); - } - }); } - /* not used yet.... waiting for the leaderboard group functionality - if(leaderboardGroupNameParamValue != null && !leaderboardGroupNameParamValue.isEmpty())) - { - sailingService.getLeaderboardGroupByName(leaderboardGroupNameParamValue, new AsyncCallback() { - @Override - public void onSuccess(LeaderboardGroupDTO leaderboardGroup) { - for(leaderboardGroup.leaderboards.contains() - if (!leaderboardNames.contains(leaderboardName)) { - createErrorPage(stringMessages.noSuchLeaderboard()); - } - } - @Override - public void onFailure(Throwable t) { - reportError("Error trying to obtain the list of leaderboard names: " + t.getMessage()); - } - }); - } - */ - if (eventName != null && !eventName.isEmpty() && raceName != null && !raceName.isEmpty()) { - sailingService.listEvents(false, new AsyncCallback>() { - @Override - public void onSuccess(List events) { - selectedRace = findRace(eventName, raceName, events); - if(selectedRace != null) { - createRaceBoardPanel(selectedRace, events, eventName, leaderboardName); - } else { - createErrorPage("Could not obtain a race with name " + raceName + " for an event with name " + eventName); - } - } + if(leaderboardGroupNameParamValue != null && !leaderboardGroupNameParamValue.isEmpty()) + leaderboardGroupName = leaderboardGroupNameParamValue; - @Override - public void onFailure(Throwable t) { - reportError("Error trying to obtain the list of events: " + t.getMessage()); - } - }); - } else { + if (eventName == null || eventName.isEmpty() || raceName == null || raceName.isEmpty()) { createErrorPage("This page requires a valid event name and race name."); + return; } + + final ParallelExecutionCallback> getLeaderboardNamesCallback = new ParallelExecutionCallback>(); + final ParallelExecutionCallback> listEventsCallback = new ParallelExecutionCallback>(); + final ParallelExecutionCallback getLeaderboardGroupByNameCallback = new ParallelExecutionCallback(); + + if (leaderboardGroupName != null) { + new ParallelExecutionHolder(getLeaderboardNamesCallback, getLeaderboardGroupByNameCallback, listEventsCallback) { + @Override + public void handleSuccess() { + checkUrlParameters(getLeaderboardNamesCallback.getData(), + getLeaderboardGroupByNameCallback.getData(), listEventsCallback.getData()); + } + @Override + public void handleFailure(Throwable t) { + reportError("Error trying to create the raceboard: " + t.getMessage()); + } + }; + } else { + new ParallelExecutionHolder(getLeaderboardNamesCallback, listEventsCallback) { + @Override + public void handleSuccess() { + checkUrlParameters(getLeaderboardNamesCallback.getData(), null, listEventsCallback.getData()); + } + @Override + public void handleFailure(Throwable t) { + reportError("Error trying to create the raceboard: " + t.getMessage()); + } + }; + } + + sailingService.listEvents(false, listEventsCallback); + sailingService.getLeaderboardNames(getLeaderboardNamesCallback); + if(leaderboardGroupName != null) + sailingService.getLeaderboardGroupByName(leaderboardGroupNameParamValue, getLeaderboardGroupByNameCallback); + } + private void checkUrlParameters(List leaderboardNames, LeaderboardGroupDTO leaderboardGroup, List events) + { + if (!leaderboardNames.contains(leaderboardName)) { + createErrorPage(stringMessages.noSuchLeaderboard()); + return; + } + + if (leaderboardGroupName != null && leaderboardGroup != null) { + boolean foundLeaderboard = false; + for(LeaderboardDTO leaderBoard: leaderboardGroup.leaderboards) { + if(leaderBoard.name.equals(leaderboardName)) { + foundLeaderboard = true; + break; + } + } + if(!foundLeaderboard) { + createErrorPage("the leaderboard is not contained in this leaderboard group."); + return; + } + } + + selectedRace = findRace(eventName, raceName, events); + if(selectedRace == null) { + createErrorPage("Could not obtain a race with name " + raceName + " for an event with name " + eventName); + return; + } + + createRaceBoardPanel(selectedRace, events, eventName, leaderboardName); + } + private RaceDTO findRace(String eventName, String raceName, List events) { for (EventDTO eventDTO : events) { if(eventDTO.name.equals(eventName)) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java index 4ce21648d14..0debcbc63c2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/RaceBoardPanel.java @@ -2,6 +2,7 @@ package com.sap.sailing.gwt.ui.raceboard; import java.util.ArrayList; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -189,16 +190,28 @@ public class RaceBoardPanel extends FormPanel implements EventDisplayer, RaceSel public void onRaceSelectionChange(List selectedRaces) { if (selectedRaces != null && !selectedRaces.isEmpty()) { RaceDTO selectedRace = racesByIdentifier.get(selectedRaces.iterator().next()); + + Date min = null; + Date max = null; + if (selectedRace.startOfTracking != null) { - timePanel.setMin(selectedRace.startOfTracking); + min = selectedRace.startOfTracking; } if (selectedRace.endOfRace != null) { - timePanel.setMax(selectedRace.endOfRace); + max = selectedRace.endOfRace; } else if (selectedRace.timePointOfNewestEvent != null) { - timePanel.setMax(selectedRace.timePointOfNewestEvent); + max = selectedRace.timePointOfNewestEvent; } - if (selectedRace.startOfRace != null) { - timer.setTime(selectedRace.startOfRace.getTime()); + + if(min != null && max != null) + timePanel.setMinMax(min, max); + + // set initial timer position + switch(timer.getPlayMode()) { + case Live: + case Replay: + timer.setTime(selectedRace.startOfRace.getTime()); + break; } timePanel.setLegMarkers(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/controls/SliderBar.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/controls/SliderBar.java index 52f1420a290..5791ad7ccd6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/controls/SliderBar.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/controls/SliderBar.java @@ -42,13 +42,12 @@ import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.RequiresResize; /** - * A widget that allows the user to select a value within a range of possible - * values using a sliding bar that responds to mouse events. + * A widget that allows the user to select a value within a range of possible values using a sliding bar that responds + * to mouse events. * *

Keyboard Events

*

- * SliderBar listens for the following key events. Holding down a key will - * repeat the action until the key is released. + * SliderBar listens for the following key events. Holding down a key will repeat the action until the key is released. *

    *
  • left arrow - shift left one step
  • *
  • right arrow - shift right one step
  • @@ -64,1145 +63,1133 @@ import com.google.gwt.user.client.ui.RequiresResize; *
      *
    • .gwt-SliderBar-shell { primary style }
    • *
    • .gwt-SliderBar-shell-focused { primary style when focused }
    • - *
    • .gwt-SliderBar-shell gwt-SliderBar-line { the line that the knob moves - * along }
    • - *
    • .gwt-SliderBar-shell gwt-SliderBar-line-sliding { the line that the knob - * moves along when sliding }
    • + *
    • .gwt-SliderBar-shell gwt-SliderBar-line { the line that the knob moves along }
    • + *
    • .gwt-SliderBar-shell gwt-SliderBar-line-sliding { the line that the knob moves along when sliding }
    • *
    • .gwt-SliderBar-shell .gwt-SliderBar-knob { the sliding knob }
    • - *
    • .gwt-SliderBar-shell .gwt-SliderBar-knob-sliding { the sliding knob when - * sliding }
    • + *
    • .gwt-SliderBar-shell .gwt-SliderBar-knob-sliding { the sliding knob when sliding }
    • *
    • * .gwt-SliderBar-shell .gwt-SliderBar-tick { the ticks along the line }
    • - *
    • .gwt-SliderBar-shell .gwt-SliderBar-ticklabel { the text labels along the - * line }
    • + *
    • .gwt-SliderBar-shell .gwt-SliderBar-ticklabel { the text labels along the line }
    • *
    */ -public class SliderBar extends FocusPanel implements RequiresResize, HasValue, - HasValueChangeHandlers { - /** - * A formatter used to format the labels displayed in the widget. - */ - public static interface LabelFormatter { +public class SliderBar extends FocusPanel implements RequiresResize, HasValue, HasValueChangeHandlers { /** - * Generate the text to display in each label based on the label's value. + * A formatter used to format the labels displayed in the widget. + */ + public static interface LabelFormatter { + /** + * Generate the text to display in each label based on the label's value. + * + * Override this method to change the text displayed within the SliderBar. + * + * @param slider + * the Slider bar + * @param value + * the value the label displays + * @return the text to display for the label + */ + String formatLabel(SliderBar slider, double value); + } + + /** + * A {@link ClientBundle} that provides images for {@link SliderBar}. + */ + public static interface SliderBarImages extends ClientBundle { + public static final SliderBarImages INSTANCE = GWT.create(SliderBarImages.class); + + /** + * An image used for the sliding knob. + * + * @return a prototype of this image + */ + @Source("slider.gif") + ImageResource slider(); + + /** + * An image used for the sliding knob. + * + * @return a prototype of this image + */ + @Source("sliderDisabled.gif") + ImageResource sliderDisabled(); + + /** + * An image used for the sliding knob while sliding. + * + * @return a prototype of this image + */ + @Source("sliderSliding.gif") + ImageResource sliderSliding(); + + @NotStrict + @Source("SliderBar.css") + CssResource sliderBarCss(); + } + + /** + * The timer used to continue to shift the knob as the user holds down one of the left/right arrow keys. Only IE + * auto-repeats, so we just keep catching the events. + */ + private class KeyTimer extends Timer { + /** + * A bit indicating that this is the first run. + */ + private boolean firstRun = true; + + /** + * The delay between shifts, which shortens as the user holds down the button. + */ + private int repeatDelay = 30; + + /** + * A bit indicating whether we are shifting to a higher or lower value. + */ + private boolean shiftRight = false; + + /** + * The number of steps to shift with each press. + */ + private int multiplier = 1; + + /** + * This method will be called when a timer fires. Override it to implement the timer's logic. + */ + @Override + public void run() { + // Highlight the knob on first run + if (firstRun) { + firstRun = false; + startSliding(true, false); + } + + // Slide the slider bar + if (shiftRight) { + setCurrentValue(curValue + multiplier * stepSize); + } else { + setCurrentValue(curValue - multiplier * stepSize); + } + + // Repeat this timer until cancelled by keyup event + schedule(repeatDelay); + } + + /** + * Schedules a timer to elapse in the future. + * + * @param delayMillis + * how long to wait before the timer elapses, in milliseconds + * @param shiftRight + * whether to shift up or not + * @param multiplier + * the number of steps to shift + */ + public void schedule(int delayMillis, boolean shiftRight, int multiplier) { + firstRun = true; + this.shiftRight = shiftRight; + this.multiplier = multiplier; + super.schedule(delayMillis); + } + } + + /** + * The current value. + */ + private Double curValue; + + /** + * The knob that slides across the line. + */ + private Image knobImage = new Image(); + + /** + * The timer used to continue to shift the knob if the user holds down a key. + */ + private KeyTimer keyTimer = new KeyTimer(); + + /** + * The elements used to display labels above the ticks. + */ + private List tickLabelElements = new ArrayList(); + + /** + * The elements used to display the marker labels. + */ + private List markerLabelElements = new ArrayList(); + + /** + * The formatter used to generate label text. + */ + private LabelFormatter tickLabelFormatter; + + /** + * The line that the knob moves over. + */ + private Element lineElement; + + /** + * The offset between the edge of the shell and the line. + */ + private int lineLeftOffset = 0; + + /** + * The maximum slider value. + */ + private Double maxValue; + + /** + * The minimum slider value. + */ + private Double minValue; + + /** + * The number of labels to show. + */ + private int numTickLabels = 0; + + /** + * The number of tick marks to show. + */ + private int numTicks = 0; + + /** + * A bit indicating whether or not we are currently sliding the slider bar due to keyboard events. + */ + private boolean slidingKeyboard = false; + + /** + * A bit indicating whether or not we are currently sliding the slider bar due to mouse events. + */ + private boolean slidingMouse = false; + + /** + * A bit indicating whether or not the slider is enabled + */ + private boolean enabled = true; + + /** + * The images used with the sliding bar. + */ + private SliderBarImages images; + + /** + * The size of the increments between knob positions. + */ + private double stepSize; + + /** + * The elements used to display tick marks, which are the vertical lines along the slider bar. + */ + private List tickElements = new ArrayList(); + + /** + * The elements used to display additional markers on the slider bar. + */ + private List markerElements = new ArrayList(); + + private List markers = new ArrayList(); + + private class Marker { + String name; + Double position; + + public Marker(String name, Double position) { + super(); + this.name = name; + this.position = position; + } + } + + /** + * Create a slider bar. + */ + public SliderBar() { + this(null, null, null); + } + + /** + * Create a slider bar. * - * Override this method to change the text displayed within the SliderBar. + * @param minValue + * the minimum value in the range + * @param maxValue + * the maximum value in the range + */ + public SliderBar(double minValue, double maxValue) { + this(minValue, maxValue, null); + } + + /** + * Create a slider bar. * - * @param slider the Slider bar - * @param value the value the label displays - * @return the text to display for the label + * @param minValue + * the minimum value in the range + * @param maxValue + * the maximum value in the range + * @param tickLabelFormatter + * the label formatter */ - String formatLabel(SliderBar slider, double value); - } - - /** - * A {@link ClientBundle} that provides images for {@link SliderBar}. - */ - public static interface SliderBarImages extends ClientBundle { - public static final SliderBarImages INSTANCE = GWT.create(SliderBarImages.class); + public SliderBar(Double minValue, Double maxValue, LabelFormatter tickLabelFormatter) { + this(minValue, maxValue, tickLabelFormatter, SliderBarImages.INSTANCE); + } /** - * An image used for the sliding knob. + * Create a slider bar. * - * @return a prototype of this image + * @param minValue + * the minimum value in the range + * @param maxValue + * the maximum value in the range + * @param tickLabelFormatter + * the label formatter + * @param images + * the images to use for the slider */ - @Source("slider.gif") - ImageResource slider(); + public SliderBar(Double minValue, Double maxValue, LabelFormatter tickLabelFormatter, SliderBarImages images) { + super(); + images.sliderBarCss().ensureInjected(); + this.minValue = minValue; + this.maxValue = maxValue; + this.images = images; + setLabelFormatter(tickLabelFormatter); + + // Create the outer shell + DOM.setStyleAttribute(getElement(), "position", "relative"); + setStyleName("gwt-SliderBar-shell"); + + // Create the line + lineElement = DOM.createDiv(); + DOM.appendChild(getElement(), lineElement); + DOM.setStyleAttribute(lineElement, "position", "absolute"); + DOM.setElementProperty(lineElement, "className", "gwt-SliderBar-line"); + + // Create the knob + knobImage.setResource(images.slider()); + Element knobElement = knobImage.getElement(); + DOM.appendChild(getElement(), knobElement); + DOM.setStyleAttribute(knobElement, "position", "absolute"); + DOM.setElementProperty(knobElement, "className", "gwt-SliderBar-knob"); + + sinkEvents(Event.MOUSEEVENTS | Event.KEYEVENTS | Event.FOCUSEVENTS); + + // workaround to render properly when parent Widget does not + // implement ProvidesResize since DOM doesn't provide element + // height and width until onModuleLoad() finishes. + Scheduler.get().scheduleDeferred(new ScheduledCommand() { + @Override + public void execute() { + onResize(); + } + }); + } + + public boolean isMinMaxInitialized() { + if (minValue == null || maxValue == null) + return false; + + return true; + } + + public HandlerRegistration addValueChangeHandler(ValueChangeHandler handler) { + return addHandler(handler, ValueChangeEvent.getType()); + } /** - * An image used for the sliding knob. + * Return the current value. * - * @return a prototype of this image + * @return the current value */ - @Source("sliderDisabled.gif") - ImageResource sliderDisabled(); + public Double getCurrentValue() { + return curValue; + } /** - * An image used for the sliding knob while sliding. + * Return the label formatter. * - * @return a prototype of this image + * @return the label formatter */ - @Source("sliderSliding.gif") - ImageResource sliderSliding(); - - @NotStrict - @Source("SliderBar.css") - CssResource sliderBarCss(); - } - - /** - * The timer used to continue to shift the knob as the user holds down one of - * the left/right arrow keys. Only IE auto-repeats, so we just keep catching - * the events. - */ - private class KeyTimer extends Timer { - /** - * A bit indicating that this is the first run. - */ - private boolean firstRun = true; + public LabelFormatter getLabelFormatter() { + return tickLabelFormatter; + } /** - * The delay between shifts, which shortens as the user holds down the - * button. + * Return the max value. + * + * @return the max value */ - private int repeatDelay = 30; + public Double getMaxValue() { + return maxValue; + } /** - * A bit indicating whether we are shifting to a higher or lower value. + * Return the minimum value. + * + * @return the minimum value */ - private boolean shiftRight = false; + public Double getMinValue() { + return minValue; + } /** - * The number of steps to shift with each press. + * Return the number of labels. + * + * @return the number of labels */ - private int multiplier = 1; + public int getNumLabels() { + return numTickLabels; + } /** - * This method will be called when a timer fires. Override it to implement - * the timer's logic. + * Return the number of ticks. + * + * @return the number of ticks + */ + public int getNumTicks() { + return numTicks; + } + + /** + * Return the step size. + * + * @return the step size + */ + public double getStepSize() { + return stepSize; + } + + /** + * Return the total range between the minimum and maximum values. + * + * @return the total range + */ + public double getTotalRange() { + if (minValue > maxValue) { + return 0; + } else { + return maxValue - minValue; + } + } + + public Double getValue() { + return curValue; + } + + /** + * @return Gets whether this widget is enabled + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Listen for events that will move the knob. + * + * @param event + * the event that occurred */ @Override - public void run() { - // Highlight the knob on first run - if (firstRun) { - firstRun = false; - startSliding(true, false); - } + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + if (enabled) { + switch (DOM.eventGetType(event)) { + // Unhighlight and cancel keyboard events + case Event.ONBLUR: + keyTimer.cancel(); + if (slidingMouse) { + DOM.releaseCapture(getElement()); + slidingMouse = false; + slideKnob(event); + stopSliding(true, true); + } else if (slidingKeyboard) { + slidingKeyboard = false; + stopSliding(true, true); + } + unhighlight(); + break; - // Slide the slider bar - if (shiftRight) { - setCurrentValue(curValue + multiplier * stepSize); - } else { - setCurrentValue(curValue - multiplier * stepSize); - } + // Highlight on focus + case Event.ONFOCUS: + highlight(); + break; - // Repeat this timer until cancelled by keyup event - schedule(repeatDelay); + // Mousewheel events + case Event.ONMOUSEWHEEL: + int velocityY = DOM.eventGetMouseWheelVelocityY(event); + DOM.eventPreventDefault(event); + if (velocityY > 0) { + shiftRight(1); + } else { + shiftLeft(1); + } + break; + + // Shift left or right on key press + case Event.ONKEYDOWN: + if (!slidingKeyboard) { + int multiplier = 1; + if (DOM.eventGetCtrlKey(event)) { + multiplier = (int) (getTotalRange() / stepSize / 10); + } + + switch (DOM.eventGetKeyCode(event)) { + case KeyCodes.KEY_HOME: + DOM.eventPreventDefault(event); + setCurrentValue(minValue); + break; + case KeyCodes.KEY_END: + DOM.eventPreventDefault(event); + setCurrentValue(maxValue); + break; + case KeyCodes.KEY_LEFT: + DOM.eventPreventDefault(event); + slidingKeyboard = true; + startSliding(false, true); + shiftLeft(multiplier); + keyTimer.schedule(400, false, multiplier); + break; + case KeyCodes.KEY_RIGHT: + DOM.eventPreventDefault(event); + slidingKeyboard = true; + startSliding(false, true); + shiftRight(multiplier); + keyTimer.schedule(400, true, multiplier); + break; + case 32: + DOM.eventPreventDefault(event); + setCurrentValue(minValue + getTotalRange() / 2); + break; + } + } + break; + // Stop shifting on key up + case Event.ONKEYUP: + keyTimer.cancel(); + if (slidingKeyboard) { + slidingKeyboard = false; + stopSliding(true, true); + } + break; + + // Mouse Events + case Event.ONMOUSEDOWN: + setFocus(true); + slidingMouse = true; + DOM.setCapture(getElement()); + startSliding(true, true); + DOM.eventPreventDefault(event); + slideKnob(event); + break; + case Event.ONMOUSEUP: + if (slidingMouse) { + DOM.releaseCapture(getElement()); + slidingMouse = false; + slideKnob(event); + stopSliding(true, true); + } + break; + case Event.ONMOUSEMOVE: + if (slidingMouse) { + slideKnob(event); + } + break; + } + } } /** - * Schedules a timer to elapse in the future. + * This method is called when the dimensions of the parent element change. Subclasses should override this method as + * needed. * - * @param delayMillis how long to wait before the timer elapses, in - * milliseconds - * @param shiftRight whether to shift up or not - * @param multiplier the number of steps to shift + * @param width + * the new client width of the element + * @param height + * the new client height of the element */ - public void schedule(int delayMillis, boolean shiftRight, int multiplier) { - firstRun = true; - this.shiftRight = shiftRight; - this.multiplier = multiplier; - super.schedule(delayMillis); + public void onResize(int width, int height) { + // Center the line in the shell + int lineWidth = lineElement.getOffsetWidth(); + lineLeftOffset = (width / 2) - (lineWidth / 2); + DOM.setStyleAttribute(lineElement, "left", lineLeftOffset + "px"); + + // Draw the other components + drawTickLabels(); + drawTicks(); + drawMarkers(); + drawMarkerLabels(); + drawKnob(); } - } - /** - * The current value. - */ - private Double curValue; - - /** - * The knob that slides across the line. - */ - private Image knobImage = new Image(); - - /** - * The timer used to continue to shift the knob if the user holds down a key. - */ - private KeyTimer keyTimer = new KeyTimer(); - - /** - * The elements used to display labels above the ticks. - */ - private List tickLabelElements = new ArrayList(); - - /** - * The elements used to display the marker labels. - */ - private List markerLabelElements = new ArrayList(); - - /** - * The formatter used to generate label text. - */ - private LabelFormatter tickLabelFormatter; - - /** - * The line that the knob moves over. - */ - private Element lineElement; - - /** - * The offset between the edge of the shell and the line. - */ - private int lineLeftOffset = 0; - - /** - * The maximum slider value. - */ - private Double maxValue; - - /** - * The minimum slider value. - */ - private Double minValue; - - /** - * The number of labels to show. - */ - private int numTickLabels = 0; - - /** - * The number of tick marks to show. - */ - private int numTicks = 0; - - /** - * A bit indicating whether or not we are currently sliding the slider bar due - * to keyboard events. - */ - private boolean slidingKeyboard = false; - - /** - * A bit indicating whether or not we are currently sliding the slider bar due - * to mouse events. - */ - private boolean slidingMouse = false; - - /** - * A bit indicating whether or not the slider is enabled - */ - private boolean enabled = true; - - /** - * The images used with the sliding bar. - */ - private SliderBarImages images; - - /** - * The size of the increments between knob positions. - */ - private double stepSize; - - /** - * The elements used to display tick marks, which are the vertical lines along - * the slider bar. - */ - private List tickElements = new ArrayList(); - - /** - * The elements used to display additional markers on the slider bar. - */ - private List markerElements = new ArrayList(); - - private List markers = new ArrayList(); - - private class Marker { - String name; - Double position; - - public Marker(String name, Double position) { - super(); - this.name = name; - this.position = position; + /** + * Redraw the progress bar when something changes the layout. + */ + public void redraw() { + if (isAttached()) { + int width = getElement().getClientWidth(); + int height = getElement().getClientHeight(); + onResize(width, height); + } } - } - - /** - * Create a slider bar. - */ - public SliderBar() { - this(null, null, null); - } - /** - * Create a slider bar. - * - * @param minValue the minimum value in the range - * @param maxValue the maximum value in the range - */ - public SliderBar(double minValue, double maxValue) { - this(minValue, maxValue, null); - } - - /** - * Create a slider bar. - * - * @param minValue the minimum value in the range - * @param maxValue the maximum value in the range - * @param tickLabelFormatter the label formatter - */ - public SliderBar(Double minValue, Double maxValue, LabelFormatter tickLabelFormatter) { - this(minValue, maxValue, tickLabelFormatter, SliderBarImages.INSTANCE); - } - - /** - * Create a slider bar. - * - * @param minValue the minimum value in the range - * @param maxValue the maximum value in the range - * @param tickLabelFormatter the label formatter - * @param images the images to use for the slider - */ - public SliderBar(Double minValue, Double maxValue, LabelFormatter tickLabelFormatter, - SliderBarImages images) { - super(); - images.sliderBarCss().ensureInjected(); - this.minValue = minValue; - this.maxValue = maxValue; - this.images = images; - setLabelFormatter(tickLabelFormatter); - - // Create the outer shell - DOM.setStyleAttribute(getElement(), "position", "relative"); - setStyleName("gwt-SliderBar-shell"); - - // Create the line - lineElement = DOM.createDiv(); - DOM.appendChild(getElement(), lineElement); - DOM.setStyleAttribute(lineElement, "position", "absolute"); - DOM.setElementProperty(lineElement, "className", "gwt-SliderBar-line"); - - // Create the knob - knobImage.setResource(images.slider()); - Element knobElement = knobImage.getElement(); - DOM.appendChild(getElement(), knobElement); - DOM.setStyleAttribute(knobElement, "position", "absolute"); - DOM.setElementProperty(knobElement, "className", "gwt-SliderBar-knob"); - - sinkEvents(Event.MOUSEEVENTS | Event.KEYEVENTS | Event.FOCUSEVENTS); - - // workaround to render properly when parent Widget does not - // implement ProvidesResize since DOM doesn't provide element - // height and width until onModuleLoad() finishes. - Scheduler.get().scheduleDeferred(new ScheduledCommand() { - @Override - public void execute() { - onResize(); - } - }); - } - - public boolean isMinMaxInitialized() { - if(minValue == null || maxValue == null) - return false; - - return true; - } - - public HandlerRegistration addValueChangeHandler(ValueChangeHandler handler) { - return addHandler(handler, ValueChangeEvent.getType()); - } - - /** - * Return the current value. - * - * @return the current value - */ - public Double getCurrentValue() { - return curValue; - } - - /** - * Return the label formatter. - * - * @return the label formatter - */ - public LabelFormatter getLabelFormatter() { - return tickLabelFormatter; - } - - /** - * Return the max value. - * - * @return the max value - */ - public Double getMaxValue() { - return maxValue; - } - - /** - * Return the minimum value. - * - * @return the minimum value - */ - public Double getMinValue() { - return minValue; - } - - /** - * Return the number of labels. - * - * @return the number of labels - */ - public int getNumLabels() { - return numTickLabels; - } - - /** - * Return the number of ticks. - * - * @return the number of ticks - */ - public int getNumTicks() { - return numTicks; - } - - /** - * Return the step size. - * - * @return the step size - */ - public double getStepSize() { - return stepSize; - } - - /** - * Return the total range between the minimum and maximum values. - * - * @return the total range - */ - public double getTotalRange() { - if (minValue > maxValue) { - return 0; - } else { - return maxValue - minValue; + /** + * Set the current value and fire the onValueChange event. + * + * @param curValue + * the current value + */ + public void setCurrentValue(Double curValue) { + setCurrentValue(curValue, true); } - } - public Double getValue() { - return curValue; - } + /** + * Set the current value and optionally fire the onValueChange event. + * + * @param curValue + * the current value + * @param fireEvent + * fire the onValue change event if true + */ + public void setCurrentValue(Double curValue, boolean fireEvent) { + // Confine the value to the range + if (!isMinMaxInitialized() || curValue == null) + return; - /** - * @return Gets whether this widget is enabled - */ - public boolean isEnabled() { - return enabled; - } + this.curValue = Math.max(minValue, Math.min(maxValue, curValue)); + double remainder = (this.curValue - minValue) % stepSize; + this.curValue -= remainder; - /** - * Listen for events that will move the knob. - * - * @param event the event that occurred - */ - @Override - public void onBrowserEvent(Event event) { - super.onBrowserEvent(event); - if (enabled) { - switch (DOM.eventGetType(event)) { - // Unhighlight and cancel keyboard events - case Event.ONBLUR: - keyTimer.cancel(); - if (slidingMouse) { - DOM.releaseCapture(getElement()); - slidingMouse = false; - slideKnob(event); - stopSliding(true, true); - } else if (slidingKeyboard) { - slidingKeyboard = false; - stopSliding(true, true); - } - unhighlight(); - break; + // Go to next step if more than halfway there + if ((remainder > (stepSize / 2)) && ((this.curValue + stepSize) <= maxValue)) { + this.curValue += stepSize; + } - // Highlight on focus - case Event.ONFOCUS: - highlight(); - break; + // Redraw the knob + drawKnob(); - // Mousewheel events - case Event.ONMOUSEWHEEL: - int velocityY = DOM.eventGetMouseWheelVelocityY(event); - DOM.eventPreventDefault(event); - if (velocityY > 0) { - shiftRight(1); - } else { - shiftLeft(1); - } - break; + // Fire the ValueChangeEvent + if (fireEvent) { + ValueChangeEvent.fire(this, this.curValue); + } + } - // Shift left or right on key press - case Event.ONKEYDOWN: - if (!slidingKeyboard) { - int multiplier = 1; - if (DOM.eventGetCtrlKey(event)) { - multiplier = (int) (getTotalRange() / stepSize / 10); + /** + * Sets whether this widget is enabled. + * + * @param enabled + * true to enable the widget, false to disable it + */ + public void setEnabled(boolean enabled) { + this.enabled = enabled; + if (enabled) { + knobImage.setResource(images.slider()); + DOM.setElementProperty(lineElement, "className", "gwt-SliderBar-line"); + } else { + knobImage.setResource(images.sliderDisabled()); + DOM.setElementProperty(lineElement, "className", "gwt-SliderBar-line gwt-SliderBar-line-disabled"); + } + redraw(); + } + + /** + * Set the label formatter. + * + * @param labelFormatter + * the label formatter + */ + public void setLabelFormatter(LabelFormatter labelFormatter) { + this.tickLabelFormatter = labelFormatter; + } + + /** + * Set the max value. + * + * @param maxValue + * the current value + */ + public void setMaxValue(Double maxValue) { + this.maxValue = maxValue; + drawTickLabels(); + resetCurrentValue(); + } + + /** + * Set the minimum value. + * + * @param minValue + * the current value + */ + public void setMinValue(Double minValue) { + this.minValue = minValue; + drawTickLabels(); + resetCurrentValue(); + } + + /** + * Set the number of tick labels to show on the line. Tick labels indicate the value of the slider at that point. + * Use this method to enable tick labels. + * + * If you set the number of tick labels equal to the total range divided by the step size, you will get a properly + * aligned "jumping" effect where the knob jumps between tick labels. + * + * Note that the number of tick labels displayed will be one more than the number you specify, so specify 1 labels + * to show labels on either end of the line. In other words, numTickLabels is really the number of slots between the + * labels. + * + * setNumTickLabels(0) will disable the labels. + * + * @param numTickLabels + * the number of tick labels to show + */ + public void setNumTickLabels(int numTickLabels) { + this.numTickLabels = numTickLabels; + drawTickLabels(); + } + + /** + * Set the number of ticks to show on the line. A tick is a vertical line that represents a division of the overall + * line. Use this method to enable ticks. + * + * If you set the number of ticks equal to the total range divided by the step size, you will get a properly aligned + * "jumping" effect where the knob jumps between ticks. + * + * Note that the number of ticks displayed will be one more than the number you specify, so specify 1 tick to show + * ticks on either end of the line. In other words, numTicks is really the number of slots between the ticks. + * + * setNumTicks(0) will disable ticks. + * + * @param numTicks + * the number of ticks to show + */ + public void setNumTicks(int numTicks) { + this.numTicks = numTicks; + drawTicks(); + } + + /** + * Set the step size. + * + * @param stepSize + * the current value + */ + public void setStepSize(double stepSize) { + this.stepSize = stepSize; + resetCurrentValue(); + } + + public void setValue(Double value) { + setCurrentValue(value, false); + } + + public void setValue(Double value, boolean fireEvent) { + setCurrentValue(value, fireEvent); + } + + /** + * Shift to the left (smaller value). + * + * @param numSteps + * the number of steps to shift + */ + public void shiftLeft(int numSteps) { + setCurrentValue(getCurrentValue() - numSteps * stepSize); + } + + /** + * Shift to the right (greater value). + * + * @param numSteps + * the number of steps to shift + */ + public void shiftRight(int numSteps) { + setCurrentValue(getCurrentValue() + numSteps * stepSize); + } + + /** + * Format the label to display above the ticks + * + * Override this method in a subclass to customize the format. By default, this method returns the integer portion + * of the value. + * + * @param value + * the value at the label + * @return the text to put in the label + */ + protected String formatTickLabel(double value) { + if (tickLabelFormatter != null) { + return tickLabelFormatter.formatLabel(this, value); + } else { + return (int) (10 * value) / 10.0 + ""; + } + } + + /** + * Get the percentage of the knob's position relative to the size of the line. The return value will be between 0.0 + * and 1.0. + * + * @return the current percent complete + */ + protected double getKnobPercent() { + // If we have no range + if (maxValue <= minValue) { + return 0; + } + + // Calculate the relative progress + double percent = (curValue - minValue) / (maxValue - minValue); + return Math.max(0.0, Math.min(1.0, percent)); + } + + /** + * This method is called immediately after a widget becomes attached to the browser's document. + */ + @Override + protected void onLoad() { + // Reset the position attribute of the parent element + DOM.setStyleAttribute(getElement(), "position", "relative"); + } + + /** + * Draw the knob where it is supposed to be relative to the line. + */ + private void drawKnob() { + if (!isAttached() || !isMinMaxInitialized()) + return; + + // Move the knob to the correct position + Element knobElement = knobImage.getElement(); + int lineWidth = lineElement.getOffsetWidth(); + int knobWidth = knobElement.getOffsetWidth(); + int knobLeftOffset = (int) (lineLeftOffset + (getKnobPercent() * lineWidth) - (knobWidth / 2)); + knobLeftOffset = Math.min(knobLeftOffset, lineLeftOffset + lineWidth - (knobWidth / 2) - 1); + DOM.setStyleAttribute(knobElement, "left", knobLeftOffset + "px"); + } + + /** + * Draw the labels along the line. + */ + private void drawTickLabels() { + if (!isAttached() || !isMinMaxInitialized()) + return; + + // Draw the tick labels + int lineWidth = lineElement.getOffsetWidth(); + if (numTickLabels > 0) { + // Create the labels or make them visible + for (int i = 0; i <= numTickLabels; i++) { + Element label = null; + if (i < tickLabelElements.size()) { + label = tickLabelElements.get(i); + } else { // Create the new label + label = DOM.createDiv(); + DOM.setStyleAttribute(label, "position", "absolute"); + DOM.setStyleAttribute(label, "display", "none"); + if (enabled) { + DOM.setElementProperty(label, "className", "gwt-SliderBar-ticklabel"); + } else { + DOM.setElementProperty(label, "className", "gwt-SliderBar-ticklabel-disabled"); + } + DOM.appendChild(getElement(), label); + tickLabelElements.add(label); + } + + // Set the label text + double value = minValue + (getTotalRange() * i / numTickLabels); + DOM.setStyleAttribute(label, "visibility", "hidden"); + DOM.setStyleAttribute(label, "display", ""); + DOM.setElementProperty(label, "innerHTML", formatTickLabel(value)); + + // Move to the left so the label width is not clipped by the + // shell + DOM.setStyleAttribute(label, "left", "0px"); + + // Position the label and make it visible + int labelWidth = label.getOffsetWidth(); + int labelLeftOffset = lineLeftOffset + (lineWidth * i / numTickLabels) - (labelWidth / 2); + labelLeftOffset = Math.min(labelLeftOffset, lineLeftOffset + lineWidth - labelWidth); + labelLeftOffset = Math.max(labelLeftOffset, lineLeftOffset); + DOM.setStyleAttribute(label, "left", labelLeftOffset + "px"); + DOM.setStyleAttribute(label, "visibility", "visible"); } - switch (DOM.eventGetKeyCode(event)) { - case KeyCodes.KEY_HOME: - DOM.eventPreventDefault(event); - setCurrentValue(minValue); - break; - case KeyCodes.KEY_END: - DOM.eventPreventDefault(event); - setCurrentValue(maxValue); - break; - case KeyCodes.KEY_LEFT: - DOM.eventPreventDefault(event); - slidingKeyboard = true; - startSliding(false, true); - shiftLeft(multiplier); - keyTimer.schedule(400, false, multiplier); - break; - case KeyCodes.KEY_RIGHT: - DOM.eventPreventDefault(event); - slidingKeyboard = true; - startSliding(false, true); - shiftRight(multiplier); - keyTimer.schedule(400, true, multiplier); - break; - case 32: - DOM.eventPreventDefault(event); - setCurrentValue(minValue + getTotalRange() / 2); - break; + // Hide unused labels + for (int i = (numTickLabels + 1); i < tickLabelElements.size(); i++) { + DOM.setStyleAttribute(tickLabelElements.get(i), "display", "none"); + } + } else { // Hide all labels + for (Element elem : tickLabelElements) { + DOM.setStyleAttribute(elem, "display", "none"); } - } - break; - // Stop shifting on key up - case Event.ONKEYUP: - keyTimer.cancel(); - if (slidingKeyboard) { - slidingKeyboard = false; - stopSliding(true, true); - } - break; - - // Mouse Events - case Event.ONMOUSEDOWN: - setFocus(true); - slidingMouse = true; - DOM.setCapture(getElement()); - startSliding(true, true); - DOM.eventPreventDefault(event); - slideKnob(event); - break; - case Event.ONMOUSEUP: - if (slidingMouse) { - DOM.releaseCapture(getElement()); - slidingMouse = false; - slideKnob(event); - stopSliding(true, true); - } - break; - case Event.ONMOUSEMOVE: - if (slidingMouse) { - slideKnob(event); - } - break; - } - } - } - - /** - * This method is called when the dimensions of the parent element change. - * Subclasses should override this method as needed. - * - * @param width the new client width of the element - * @param height the new client height of the element - */ - public void onResize(int width, int height) { - // Center the line in the shell - int lineWidth = lineElement.getOffsetWidth(); - lineLeftOffset = (width / 2) - (lineWidth / 2); - DOM.setStyleAttribute(lineElement, "left", lineLeftOffset + "px"); - - // Draw the other components - drawTickLabels(); - drawTicks(); - drawMarkers(); - drawMarkerLabels(); - drawKnob(); - } - - /** - * Redraw the progress bar when something changes the layout. - */ - public void redraw() { - if (isAttached()) { - int width = getElement().getClientWidth(); - int height = getElement().getClientHeight(); - onResize(width, height); - } - } - - /** - * Set the current value and fire the onValueChange event. - * - * @param curValue the current value - */ - public void setCurrentValue(Double curValue) { - setCurrentValue(curValue, true); - } - - /** - * Set the current value and optionally fire the onValueChange event. - * - * @param curValue the current value - * @param fireEvent fire the onValue change event if true - */ - public void setCurrentValue(Double curValue, boolean fireEvent) { - // Confine the value to the range - if(!isMinMaxInitialized() || curValue == null) - return; - - this.curValue = Math.max(minValue, Math.min(maxValue, curValue)); - double remainder = (this.curValue - minValue) % stepSize; - this.curValue -= remainder; - - // Go to next step if more than halfway there - if ((remainder > (stepSize / 2)) && ((this.curValue + stepSize) <= maxValue)) { - this.curValue += stepSize; - } - - // Redraw the knob - drawKnob(); - - // Fire the ValueChangeEvent - if (fireEvent) { - ValueChangeEvent.fire(this, this.curValue); - } - } - - /** - * Sets whether this widget is enabled. - * - * @param enabled true to enable the widget, false to disable it - */ - public void setEnabled(boolean enabled) { - this.enabled = enabled; - if (enabled) { - knobImage.setResource(images.slider()); - DOM.setElementProperty(lineElement, "className", "gwt-SliderBar-line"); - } else { - knobImage.setResource(images.sliderDisabled()); - DOM.setElementProperty(lineElement, "className", - "gwt-SliderBar-line gwt-SliderBar-line-disabled"); - } - redraw(); - } - - /** - * Set the label formatter. - * - * @param labelFormatter the label formatter - */ - public void setLabelFormatter(LabelFormatter labelFormatter) { - this.tickLabelFormatter = labelFormatter; - } - - /** - * Set the max value. - * - * @param maxValue the current value - */ - public void setMaxValue(Double maxValue) { - this.maxValue = maxValue; - drawTickLabels(); - resetCurrentValue(); - } - - /** - * Set the minimum value. - * - * @param minValue the current value - */ - public void setMinValue(Double minValue) { - this.minValue = minValue; - drawTickLabels(); - resetCurrentValue(); - } - - /** - * Set the number of tick labels to show on the line. Tick labels indicate the value of - * the slider at that point. Use this method to enable tick labels. - * - * If you set the number of tick labels equal to the total range divided by the - * step size, you will get a properly aligned "jumping" effect where the knob - * jumps between tick labels. - * - * Note that the number of tick labels displayed will be one more than the number - * you specify, so specify 1 labels to show labels on either end of the line. - * In other words, numTickLabels is really the number of slots between the labels. - * - * setNumTickLabels(0) will disable the labels. - * - * @param numTickLabels the number of tick labels to show - */ - public void setNumTickLabels(int numTickLabels) { - this.numTickLabels = numTickLabels; - drawTickLabels(); - } - - /** - * Set the number of ticks to show on the line. A tick is a vertical line that - * represents a division of the overall line. Use this method to enable ticks. - * - * If you set the number of ticks equal to the total range divided by the step - * size, you will get a properly aligned "jumping" effect where the knob jumps - * between ticks. - * - * Note that the number of ticks displayed will be one more than the number - * you specify, so specify 1 tick to show ticks on either end of the line. In - * other words, numTicks is really the number of slots between the ticks. - * - * setNumTicks(0) will disable ticks. - * - * @param numTicks the number of ticks to show - */ - public void setNumTicks(int numTicks) { - this.numTicks = numTicks; - drawTicks(); - } - - /** - * Set the step size. - * - * @param stepSize the current value - */ - public void setStepSize(double stepSize) { - this.stepSize = stepSize; - resetCurrentValue(); - } - - public void setValue(Double value) { - setCurrentValue(value, false); - } - - public void setValue(Double value, boolean fireEvent) { - setCurrentValue(value, fireEvent); - } - - /** - * Shift to the left (smaller value). - * - * @param numSteps the number of steps to shift - */ - public void shiftLeft(int numSteps) { - setCurrentValue(getCurrentValue() - numSteps * stepSize); - } - - /** - * Shift to the right (greater value). - * - * @param numSteps the number of steps to shift - */ - public void shiftRight(int numSteps) { - setCurrentValue(getCurrentValue() + numSteps * stepSize); - } - - /** - * Format the label to display above the ticks - * - * Override this method in a subclass to customize the format. By default, - * this method returns the integer portion of the value. - * - * @param value the value at the label - * @return the text to put in the label - */ - protected String formatTickLabel(double value) { - if (tickLabelFormatter != null) { - return tickLabelFormatter.formatLabel(this, value); - } else { - return (int) (10 * value) / 10.0 + ""; - } - } - - /** - * Get the percentage of the knob's position relative to the size of the line. - * The return value will be between 0.0 and 1.0. - * - * @return the current percent complete - */ - protected double getKnobPercent() { - // If we have no range - if (maxValue <= minValue) { - return 0; - } - - // Calculate the relative progress - double percent = (curValue - minValue) / (maxValue - minValue); - return Math.max(0.0, Math.min(1.0, percent)); - } - - /** - * This method is called immediately after a widget becomes attached to the - * browser's document. - */ - @Override - protected void onLoad() { - // Reset the position attribute of the parent element - DOM.setStyleAttribute(getElement(), "position", "relative"); - } - - /** - * Draw the knob where it is supposed to be relative to the line. - */ - private void drawKnob() { - // Abort if not attached - if (!isAttached()) { - return; - } - - if(!isMinMaxInitialized()) - return; - - // Move the knob to the correct position - Element knobElement = knobImage.getElement(); - int lineWidth = lineElement.getOffsetWidth(); - int knobWidth = knobElement.getOffsetWidth(); - int knobLeftOffset = (int) (lineLeftOffset + (getKnobPercent() * lineWidth) - (knobWidth / 2)); - knobLeftOffset = Math.min(knobLeftOffset, lineLeftOffset + lineWidth - (knobWidth / 2) - 1); - DOM.setStyleAttribute(knobElement, "left", knobLeftOffset + "px"); - } - - /** - * Draw the labels along the line. - */ - private void drawTickLabels() { - // Abort if not attached - if (!isAttached()) - return; - - if(!isMinMaxInitialized()) - return; - - // Draw the tick labels - int lineWidth = lineElement.getOffsetWidth(); - if (numTickLabels > 0) { - // Create the labels or make them visible - for (int i = 0; i <= numTickLabels; i++) { - Element label = null; - if (i < tickLabelElements.size()) { - label = tickLabelElements.get(i); - } else { // Create the new label - label = DOM.createDiv(); - DOM.setStyleAttribute(label, "position", "absolute"); - DOM.setStyleAttribute(label, "display", "none"); - if (enabled) { - DOM.setElementProperty(label, "className", "gwt-SliderBar-ticklabel"); - } else { - DOM.setElementProperty(label, "className", "gwt-SliderBar-ticklabel-disabled"); - } - DOM.appendChild(getElement(), label); - tickLabelElements.add(label); } - - // Set the label text - double value = minValue + (getTotalRange() * i / numTickLabels); - DOM.setStyleAttribute(label, "visibility", "hidden"); - DOM.setStyleAttribute(label, "display", ""); - DOM.setElementProperty(label, "innerHTML", formatTickLabel(value)); - - // Move to the left so the label width is not clipped by the - // shell - DOM.setStyleAttribute(label, "left", "0px"); - - // Position the label and make it visible - int labelWidth = label.getOffsetWidth(); - int labelLeftOffset = lineLeftOffset + (lineWidth * i / numTickLabels) - (labelWidth / 2); - labelLeftOffset = Math.min(labelLeftOffset, lineLeftOffset + lineWidth - labelWidth); - labelLeftOffset = Math.max(labelLeftOffset, lineLeftOffset); - DOM.setStyleAttribute(label, "left", labelLeftOffset + "px"); - DOM.setStyleAttribute(label, "visibility", "visible"); - } - - // Hide unused labels - for (int i = (numTickLabels + 1); i < tickLabelElements.size(); i++) { - DOM.setStyleAttribute(tickLabelElements.get(i), "display", "none"); - } - } else { // Hide all labels - for (Element elem : tickLabelElements) { - DOM.setStyleAttribute(elem, "display", "none"); - } - } - } - - /** - * Draw the tick along the line. - */ - private void drawTicks() { - // Abort if not attached - if (!isAttached()) { - return; } - if(!isMinMaxInitialized()) - return; + /** + * Draw the tick along the line. + */ + private void drawTicks() { + if (!isAttached() || !isMinMaxInitialized()) + return; - // Draw the ticks - int lineWidth = lineElement.getOffsetWidth(); - if (numTicks > 0) { - // Create the ticks or make them visible - for (int i = 0; i <= numTicks; i++) { - Element tick = null; - if (i < tickElements.size()) { - tick = tickElements.get(i); - } else { // Create the new tick - tick = DOM.createDiv(); - DOM.setStyleAttribute(tick, "position", "absolute"); - DOM.setStyleAttribute(tick, "display", "none"); - DOM.appendChild(getElement(), tick); - tickElements.add(tick); + // Draw the ticks + int lineWidth = lineElement.getOffsetWidth(); + if (numTicks > 0) { + // Create the ticks or make them visible + for (int i = 0; i <= numTicks; i++) { + Element tick = null; + if (i < tickElements.size()) { + tick = tickElements.get(i); + } else { // Create the new tick + tick = DOM.createDiv(); + DOM.setStyleAttribute(tick, "position", "absolute"); + DOM.setStyleAttribute(tick, "display", "none"); + DOM.appendChild(getElement(), tick); + tickElements.add(tick); + } + if (enabled) { + DOM.setElementProperty(tick, "className", "gwt-SliderBar-tick"); + } else { + DOM.setElementProperty(tick, "className", "gwt-SliderBar-tick gwt-SliderBar-tick-disabled"); + } + // Position the tick and make it visible + DOM.setStyleAttribute(tick, "visibility", "hidden"); + DOM.setStyleAttribute(tick, "display", ""); + int tickWidth = tick.getOffsetWidth(); + int tickLeftOffset = lineLeftOffset + (lineWidth * i / numTicks) - (tickWidth / 2); + tickLeftOffset = Math.min(tickLeftOffset, lineLeftOffset + lineWidth - tickWidth); + DOM.setStyleAttribute(tick, "left", tickLeftOffset + "px"); + DOM.setStyleAttribute(tick, "visibility", "visible"); + } + + // Hide unused ticks + for (int i = (numTicks + 1); i < tickElements.size(); i++) { + DOM.setStyleAttribute(tickElements.get(i), "display", "none"); + } + } else { // Hide all ticks + for (Element elem : tickElements) { + DOM.setStyleAttribute(elem, "display", "none"); + } } - if (enabled) { - DOM.setElementProperty(tick, "className", "gwt-SliderBar-tick"); - } else { - DOM.setElementProperty(tick, "className", - "gwt-SliderBar-tick gwt-SliderBar-tick-disabled"); + } + + /** + * Draw the markers. + */ + private void drawMarkers() { + if (!isAttached() || !isMinMaxInitialized()) + return; + + int numMarkers = markers.size(); + // Draw the markers + int lineWidth = lineElement.getOffsetWidth(); + if (numMarkers > 0) { + // Create the markers or make them visible + for (int i = 0; i < numMarkers; i++) { + Marker marker = markers.get(i); + Element markerElem = null; + if (i < markerElements.size()) { + markerElem = markerElements.get(i); + } else { // Create the new markes + markerElem = DOM.createDiv(); + DOM.setStyleAttribute(markerElem, "position", "absolute"); + DOM.setStyleAttribute(markerElem, "display", "none"); + DOM.appendChild(getElement(), markerElem); + markerElements.add(markerElem); + } + if (enabled) { + DOM.setElementProperty(markerElem, "className", "gwt-SliderBar-mark"); + } else { + DOM.setElementProperty(markerElem, "className", "gwt-SliderBar-mark gwt-SliderBar-mark-disabled"); + } + // Position the marker and make it visible + DOM.setStyleAttribute(markerElem, "visibility", "hidden"); + DOM.setStyleAttribute(markerElem, "display", ""); + double markerLinePosition = (marker.position - minValue) * lineWidth / getTotalRange(); + int markerWidth = markerElem.getOffsetWidth(); + int markerLeftOffset = lineLeftOffset + (int) markerLinePosition - (markerWidth / 2); + markerLeftOffset = Math.min(markerLeftOffset, lineLeftOffset + lineWidth - markerWidth); + DOM.setStyleAttribute(markerElem, "left", markerLeftOffset + "px"); + DOM.setStyleAttribute(markerElem, "visibility", "visible"); + } + + // Hide unused markers + for (int i = (numMarkers + 1); i < markerElements.size(); i++) { + DOM.setStyleAttribute(tickElements.get(i), "display", "none"); + } + } else { // Hide all markers + for (Element elem : markerElements) { + DOM.setStyleAttribute(elem, "display", "none"); + } } - // Position the tick and make it visible - DOM.setStyleAttribute(tick, "visibility", "hidden"); - DOM.setStyleAttribute(tick, "display", ""); - int tickWidth = tick.getOffsetWidth(); - int tickLeftOffset = lineLeftOffset + (lineWidth * i / numTicks) - (tickWidth / 2); - tickLeftOffset = Math.min(tickLeftOffset, lineLeftOffset + lineWidth - tickWidth); - DOM.setStyleAttribute(tick, "left", tickLeftOffset + "px"); - DOM.setStyleAttribute(tick, "visibility", "visible"); - } - - // Hide unused ticks - for (int i = (numTicks + 1); i < tickElements.size(); i++) { - DOM.setStyleAttribute(tickElements.get(i), "display", "none"); - } - } else { // Hide all ticks - for (Element elem : tickElements) { - DOM.setStyleAttribute(elem, "display", "none"); - } - } - } - - /** - * Draw the markers. - */ - private void drawMarkers() { - // Abort if not attached - if (!isAttached()) { - return; } - if(!isMinMaxInitialized()) - return; + /** + * Draw the marker labels. + */ + private void drawMarkerLabels() { + if (!isAttached() || !isMinMaxInitialized()) + return; - int numMarkers = markers.size(); - // Draw the markers - int lineWidth = lineElement.getOffsetWidth(); - if (numMarkers > 0) { - // Create the markers or make them visible - for (int i = 0; i < numMarkers; i++) { - Marker marker = markers.get(i); - Element markerElem = null; - if (i < markerElements.size()) { - markerElem = markerElements.get(i); - } else { // Create the new markes - markerElem = DOM.createDiv(); - DOM.setStyleAttribute(markerElem, "position", "absolute"); - DOM.setStyleAttribute(markerElem, "display", "none"); - DOM.appendChild(getElement(), markerElem); - markerElements.add(markerElem); + int numMarkers = markers.size(); + // Draw the marker labels + int lineWidth = lineElement.getOffsetWidth(); + if (numMarkers > 0) { + // Create the labels or make them visible + for (int i = 0; i < numMarkers; i++) { + Marker marker = markers.get(i); + Element label = null; + if (i < markerLabelElements.size()) { + label = markerLabelElements.get(i); + } else { // Create the new label + label = DOM.createDiv(); + DOM.setStyleAttribute(label, "position", "absolute"); + DOM.setStyleAttribute(label, "display", "none"); + if (enabled) { + DOM.setElementProperty(label, "className", "gwt-SliderBar-markerlabel"); + } else { + DOM.setElementProperty(label, "className", "gwt-SliderBar-markerlabel-disabled"); + } + DOM.appendChild(getElement(), label); + markerLabelElements.add(label); + } + + // Set the marker label text + DOM.setStyleAttribute(label, "visibility", "hidden"); + DOM.setStyleAttribute(label, "display", ""); + DOM.setElementProperty(label, "innerHTML", marker.name); + + // Move to the left so the label width is not clipped by the + // shell + DOM.setStyleAttribute(label, "left", "0px"); + + // Position the label and make it visible + double markerLinePosition = (marker.position - minValue) * lineWidth / getTotalRange(); + int labelWidth = label.getOffsetWidth(); + int labelLeftOffset = lineLeftOffset + (int) markerLinePosition - (labelWidth / 2); + labelLeftOffset = Math.min(labelLeftOffset, lineLeftOffset + lineWidth - labelWidth); + + DOM.setStyleAttribute(label, "left", labelLeftOffset + "px"); + DOM.setStyleAttribute(label, "visibility", "visible"); + } + + // Hide unused labels + for (int i = (numMarkers + 1); i < markerLabelElements.size(); i++) { + DOM.setStyleAttribute(markerLabelElements.get(i), "display", "none"); + } + } else { // Hide all labels + for (Element elem : markerLabelElements) { + DOM.setStyleAttribute(elem, "display", "none"); + } } - if (enabled) { - DOM.setElementProperty(markerElem, "className", "gwt-SliderBar-mark"); - } else { - DOM.setElementProperty(markerElem, "className", - "gwt-SliderBar-mark gwt-SliderBar-mark-disabled"); + } + + /** + * Highlight this widget. + */ + private void highlight() { + String styleName = getStylePrimaryName(); + DOM.setElementProperty(getElement(), "className", styleName + " " + styleName + "-focused"); + } + + /** + * Reset the progress to constrain the progress to the current range and redraw the knob as needed. + */ + private void resetCurrentValue() { + setCurrentValue(getCurrentValue()); + } + + /** + * Slide the knob to a new location. + * + * @param event + * the mouse event + */ + private void slideKnob(Event event) { + int x = DOM.eventGetClientX(event); + if (x > 0) { + int lineWidth = lineElement.getOffsetWidth(); + int lineLeft = lineElement.getAbsoluteLeft(); + double percent = (double) (x - lineLeft) / lineWidth * 1.0; + setCurrentValue(getTotalRange() * percent + minValue, true); } - // Position the marker and make it visible - DOM.setStyleAttribute(markerElem, "visibility", "hidden"); - DOM.setStyleAttribute(markerElem, "display", ""); - double markerLinePosition = (marker.position - minValue) * lineWidth / getTotalRange(); - int markerWidth = markerElem.getOffsetWidth(); - int markerLeftOffset = lineLeftOffset + (int) markerLinePosition - (markerWidth / 2); - markerLeftOffset = Math.min(markerLeftOffset, lineLeftOffset + lineWidth - markerWidth); - DOM.setStyleAttribute(markerElem, "left", markerLeftOffset + "px"); - DOM.setStyleAttribute(markerElem, "visibility", "visible"); - } - - // Hide unused markers - for (int i = (numMarkers + 1); i < markerElements.size(); i++) { - DOM.setStyleAttribute(tickElements.get(i), "display", "none"); - } - } else { // Hide all markers - for (Element elem : markerElements) { - DOM.setStyleAttribute(elem, "display", "none"); - } } - } - /** - * Draw the marker labels. - */ - private void drawMarkerLabels() { - // Abort if not attached - if (!isAttached()) - return; - - if(!isMinMaxInitialized()) - return; - - int numMarkers = markers.size(); - // Draw the marker labels - int lineWidth = lineElement.getOffsetWidth(); - if (numMarkers > 0) { - // Create the labels or make them visible - for (int i = 0; i < numMarkers; i++) { - Marker marker = markers.get(i); - Element label = null; - if (i < markerLabelElements.size()) { - label = markerLabelElements.get(i); - } else { // Create the new label - label = DOM.createDiv(); - DOM.setStyleAttribute(label, "position", "absolute"); - DOM.setStyleAttribute(label, "display", "none"); - if (enabled) { - DOM.setElementProperty(label, "className", "gwt-SliderBar-markerlabel"); - } else { - DOM.setElementProperty(label, "className", "gwt-SliderBar-markerlabel-disabled"); - } - DOM.appendChild(getElement(), label); - markerLabelElements.add(label); + /** + * Start sliding the knob. + * + * @param highlight + * true to change the style + * @param fireEvent + * true to fire the event + */ + private void startSliding(boolean highlight, boolean fireEvent) { + if (highlight) { + DOM.setElementProperty(lineElement, "className", "gwt-SliderBar-line gwt-SliderBar-line-sliding"); + DOM.setElementProperty(knobImage.getElement(), "className", "gwt-SliderBar-knob gwt-SliderBar-knob-sliding"); + knobImage.setResource(images.sliderSliding()); } - - // Set the marker label text - DOM.setStyleAttribute(label, "visibility", "hidden"); - DOM.setStyleAttribute(label, "display", ""); - DOM.setElementProperty(label, "innerHTML", marker.name); - - // Move to the left so the label width is not clipped by the - // shell - DOM.setStyleAttribute(label, "left", "0px"); - - // Position the label and make it visible - double markerLinePosition = (marker.position - minValue) * lineWidth / getTotalRange(); - int labelWidth = label.getOffsetWidth(); - int labelLeftOffset = lineLeftOffset + (int) markerLinePosition - (labelWidth / 2); - labelLeftOffset = Math.min(labelLeftOffset, lineLeftOffset + lineWidth - labelWidth); - - -// int labelLeftOffset = lineLeftOffset + (int) markerLinePosition - (labelWidth / 2); -// labelLeftOffset = Math.min(labelLeftOffset, lineLeftOffset + lineWidth - labelWidth); -// labelLeftOffset = Math.max(labelLeftOffset, lineLeftOffset); - DOM.setStyleAttribute(label, "left", labelLeftOffset + "px"); - DOM.setStyleAttribute(label, "visibility", "visible"); - } - - // Hide unused labels - for (int i = (numMarkers + 1); i < markerLabelElements.size(); i++) { - DOM.setStyleAttribute(markerLabelElements.get(i), "display", "none"); - } - } else { // Hide all labels - for (Element elem : markerLabelElements) { - DOM.setStyleAttribute(elem, "display", "none"); - } } - } - - /** - * Highlight this widget. - */ - private void highlight() { - String styleName = getStylePrimaryName(); - DOM.setElementProperty(getElement(), "className", styleName + " " + styleName + "-focused"); - } - /** - * Reset the progress to constrain the progress to the current range and - * redraw the knob as needed. - */ - private void resetCurrentValue() { - setCurrentValue(getCurrentValue()); - } + /** + * Stop sliding the knob. + * + * @param unhighlight + * true to change the style + * @param fireEvent + * true to fire the event + */ + private void stopSliding(boolean unhighlight, boolean fireEvent) { + if (unhighlight) { + DOM.setElementProperty(lineElement, "className", "gwt-SliderBar-line"); - /** - * Slide the knob to a new location. - * - * @param event the mouse event - */ - private void slideKnob(Event event) { - int x = DOM.eventGetClientX(event); - if (x > 0) { - int lineWidth = lineElement.getOffsetWidth(); - int lineLeft = lineElement.getAbsoluteLeft(); - double percent = (double) (x - lineLeft) / lineWidth * 1.0; - setCurrentValue(getTotalRange() * percent + minValue, true); + DOM.setElementProperty(knobImage.getElement(), "className", "gwt-SliderBar-knob"); + knobImage.setResource(images.slider()); + } } - } - /** - * Start sliding the knob. - * - * @param highlight true to change the style - * @param fireEvent true to fire the event - */ - private void startSliding(boolean highlight, boolean fireEvent) { - if (highlight) { - DOM.setElementProperty(lineElement, "className", - "gwt-SliderBar-line gwt-SliderBar-line-sliding"); - DOM.setElementProperty(knobImage.getElement(), "className", - "gwt-SliderBar-knob gwt-SliderBar-knob-sliding"); - knobImage.setResource(images.sliderSliding()); + /** + * Unhighlight this widget. + */ + private void unhighlight() { + DOM.setElementProperty(getElement(), "className", getStylePrimaryName()); } - } - /** - * Stop sliding the knob. - * - * @param unhighlight true to change the style - * @param fireEvent true to fire the event - */ - private void stopSliding(boolean unhighlight, boolean fireEvent) { - if (unhighlight) { - DOM.setElementProperty(lineElement, "className", "gwt-SliderBar-line"); - - DOM.setElementProperty(knobImage.getElement(), "className", "gwt-SliderBar-knob"); - knobImage.setResource(images.slider()); + @Override + public void onResize() { + redraw(); } - } - /** - * Unhighlight this widget. - */ - private void unhighlight() { - DOM.setElementProperty(getElement(), "className", getStylePrimaryName()); - } + public void clearMarkers() { + markers.clear(); + } - @Override - public void onResize() { - redraw(); - } - - public boolean addMarker(String markerName, Double markerPosition) { - return markers.add(new Marker(markerName, markerPosition)); - } + public boolean addMarker(String markerName, Double markerPosition) { + return markers.add(new Marker(markerName, markerPosition)); + } - public boolean setMarker(String markerName, Double markerPosition) { - Marker marker = findMarkerByName(markerName); - if(marker != null) { - marker.position = markerPosition; - return true; - } - return false; - } + public boolean setMarker(String markerName, Double markerPosition) { + Marker marker = findMarkerByName(markerName); + if (marker != null) { + marker.position = markerPosition; + return true; + } + return false; + } - public boolean removeMarker(String markerName) { - Marker marker = findMarkerByName(markerName); - if(marker != null) { - return markers.remove(marker); - } - return false; - } + public boolean removeMarker(String markerName) { + Marker marker = findMarkerByName(markerName); + if (marker != null) { + return markers.remove(marker); + } + return false; + } - public Iterator getMarkers() - { - return markers.iterator(); - } + public Iterator getMarkers() { + return markers.iterator(); + } - private Marker findMarkerByName(String markerName) { - for(Marker marker: markers) { - if (marker.name.equals(markerName)) { - return marker; - } - } - return null; - } + private Marker findMarkerByName(String markerName) { + for (Marker marker : markers) { + if (marker.name.equals(markerName)) { + return marker; + } + } + return null; + } }