/* * Copyright (c) 2006 Stiftung Deutsches Elektronen-Synchroton, Member of the Helmholtz Association, * (DESY), HAMBURG, GERMANY. * * THIS SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "../AS IS" BASIS. WITHOUT WARRANTY OF ANY * KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. SHOULD THE SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, THE USER ASSUMES * THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY * CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY SOFTWARE IS AUTHORIZED HEREUNDER * EXCEPT UNDER THIS DISCLAIMER. DESY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, * ENHANCEMENTS, OR MODIFICATIONS. THE FULL LICENSE SPECIFYING FOR THE SOFTWARE THE REDISTRIBUTION, * MODIFICATION, USAGE AND OTHER RIGHTS AND OBLIGATIONS IS INCLUDED WITH THE DISTRIBUTION OF THIS * PROJECT IN THE FILE LICENSE.HTML. IF THE LICENSE IS NOT INCLUDED YOU MAY FIND A COPY AT * HTTP://WWW.DESY.DE/LEGAL/LICENSE.HTM */ package org.csstudio.sds.components.ui.internal.figures; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.math.BigDecimal; import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; import org.csstudio.sds.ui.figures.BorderAdapter; import org.csstudio.sds.ui.figures.CrossedOutAdapter; import org.csstudio.sds.ui.figures.IBorderEquippedWidget; import org.csstudio.sds.ui.figures.ICrossedFigure; import org.csstudio.sds.ui.figures.IRhombusEquippedWidget; import org.csstudio.sds.ui.figures.RhombusAdapter; import org.csstudio.ui.util.CustomMediaFactory; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.draw2d.BorderLayout; import org.eclipse.draw2d.ColorConstants; import org.eclipse.draw2d.Ellipse; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.Label; import org.eclipse.draw2d.Orientable; import org.eclipse.draw2d.Panel; import org.eclipse.draw2d.RangeModel; import org.eclipse.draw2d.SchemeBorder; import org.eclipse.draw2d.ScrollBar; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; /** * A slider figure. * * @author Sven Wende * @version $Revision: 1.30 $ * */ public final class SimpleSliderFigure extends Panel implements IAdaptable { /** * Listeners that react on slider events. */ private final List<ISliderListener> _sliderListeners; /** * A border adapter, which covers all border handlings. */ private IBorderEquippedWidget _borderAdapter; /** * The scroll bar figure. */ private final MyScrollBar _scrollBar; /** * A label, which display the current value. */ private final Label _valueLabel; /** * Lower border of the displayed value. */ private int _min = 0; /** * Upper border of the displayed value. */ private int _max = 100; /** * The current value. */ private int _currentValue = 30; /** * The precision of the scrollbar. */ private int _scrollbarPrecision = 100; /** * The potenz for the precision. */ private int _decimalPlaces = 2; /** * The minimum wide for the slider. */ private int _sliderWide = 5; /** * The "show value as text" flag. */ private boolean _showValueAsText = false; /** * The original minimum value. */ private double _originalMin; /** * The original maximum value. */ private double _originalMax; /** * The original manual value. */ private double _originalManVal; /** * The original value. */ private double _originalVal; /** * Flag which is used to disable slider events. When the current value is set on the scrollbar, * eventing must be turned off. */ private boolean _populateEvents = true; private boolean _enable; private CrossedOutAdapter _crossedOutAdapter; private RhombusAdapter _rhombusAdapter; /** * Standard constructor. */ public SimpleSliderFigure() { _sliderListeners = new ArrayList<ISliderListener>(); BorderLayout layout = new BorderLayout(); layout.setVerticalSpacing(2); layout.setHorizontalSpacing(2); setLayoutManager(layout); _valueLabel = new Label(); add(_valueLabel, BorderLayout.TOP); _valueLabel.setVisible(_showValueAsText); _scrollBar = createScrollbarFigure(); add(_scrollBar, BorderLayout.CENTER); } @Override public void paint(final Graphics graphics) { super.paint(graphics); _crossedOutAdapter.paint(graphics); _rhombusAdapter.paint(graphics); } /** * Creates the scrollbar. * * @return the scrollbar figure */ private MyScrollBar createScrollbarFigure() { MyScrollBar bar = new MyScrollBar(); bar.setExtent(5); bar.setMaximum(1000); bar.setMinimum(1); bar.setValue(400); bar.setStepIncrement(1); bar.setOrientation(Orientable.VERTICAL); bar.setBackgroundColor(ColorConstants.blue); Ellipse thumb = new Ellipse(); thumb.setSize(new Dimension(40, 40)); thumb.setFont(CustomMediaFactory.getInstance().getDefaultFont(SWT.BOLD)); thumb.setBackgroundColor(ColorConstants.red); thumb.setBorder(new SchemeBorder(SchemeBorder.SCHEMES.RIDGED)); bar.validate(); // add listener bar.addPropertyChangeListener(RangeModel.PROPERTY_VALUE, new PropertyChangeListener() { @Override public void propertyChange(final PropertyChangeEvent event) { fireManualValueChange((Integer) event.getNewValue()); } }); return bar; } /** * Inform all slider listeners, that the manual value has changed. * * @param newManualValue * the new manual value */ private void fireManualValueChange(final int newManualValue) { int tmp = newManualValue; if (tmp < _min) { tmp = _min; } if (tmp > _max) { tmp = _max; } if (_populateEvents) { for (ISliderListener l : _sliderListeners) { l.sliderValueChanged( ((double) tmp) / _scrollbarPrecision); } } } /** * Set the "populate events" flag. * * @param populateEvents * the "populate events" flag. */ public void setPopulateEvents(final boolean populateEvents) { _populateEvents = populateEvents; } /** * Sets if the current value should also be shown as text. * * @param showValueAsText * True if the value should be shown as text, false otherwise */ public void setShowValueAsText(final boolean showValueAsText) { _showValueAsText = showValueAsText; _valueLabel.setVisible(_showValueAsText); } /** * Set the minimum value. * * @param min * The minimum value. */ public void setMin(final double min) { _originalMin = min; updateScrollbar(); } /** * Set the maximum value. * * @param max * The maximum value. */ public void setMax(final double max) { _originalMax = max; updateScrollbar(); } /** * Refreshes the scroolbar. */ private void updateScrollbar() { // if (isEnabled()) { _min = (int) (_originalMin * _scrollbarPrecision); _max = (int) (_originalMax * _scrollbarPrecision); _scrollBar.setMinimum(_min); _scrollBar.setMaximum(_max + _sliderWide); _currentValue = (int) Math.round(_originalVal * _scrollbarPrecision); int settedValue = _currentValue; // update scrollbar if (_currentValue < _min) { // current value is out of the sliders range -> disable the // slider // 07.01.08 the slider shouldn't be disabled any more // _scrollBar.setEnabled(false); // _scrollBar.setValue(_currentValue); settedValue = _min; } else if (_currentValue > _max) { settedValue = _max; } _scrollBar.setValue(settedValue); _scrollBar.invalidate(); // } } /** * Sets the real max value for the scrollbar based on the given max value. * * @param max * The base for the real max value */ private void setScrollbarMax(final int max) { _scrollBar.setMaximum(max + _sliderWide); } /** * Sets the count of decimal places for this slider. * * @param decimalPlaces * The precision */ public void setDecimalPlaces(final int decimalPlaces) { _decimalPlaces = decimalPlaces; this.updateValueText(); } /** * Gets the precision of this slider. * * @return The precision */ public int getDecimalPlaces() { return _decimalPlaces; } /** * Sets the value for the precision of this slider. * * @param precision * The precision */ private void setScrollbarPrecision(final int precision) { // double min = this.getDoubleFor(_min); // double max = this.getDoubleFor(_max); int minWide = _sliderWide / _scrollbarPrecision; // double value = this.getDoubleFor(_currentValue); // double manualValue = this.getDoubleFor(_manualValue); _scrollbarPrecision = precision; // this.setMin(min); // this.setMax(max); this.setSliderWide(minWide); // this.setValue(value); // this.setManualValue(manualValue); updateScrollbar(); } /** * Sets the wide for the slider. * * @param wide * The wide */ public void setSliderWide(final int wide) { _sliderWide = wide * _scrollbarPrecision; this.setScrollbarMax(_max); _scrollBar.setExtent(_sliderWide); } /** * Gets the slider wide. * * @return int The slider wide */ public int getSliderWide() { return (_sliderWide / _scrollbarPrecision); } /** * Set the increment value. * * @param increment * The increment value. */ public void setIncrement(final double increment) { this.setScrollbarPrecision((int) Math.pow(10, this.getCountOfDecimals(increment))); int inc = (int) (increment * _scrollbarPrecision); if (inc == 0) { inc = 1; } _scrollBar.setStepIncrement(inc); _scrollBar.setPageIncrement(inc); } /** * Gets the count of numbers after the comma. * * @param value * The double value * @return int The count of numbers after the comma */ private int getCountOfDecimals(final double value) { // This is a bit of a hack: because the double value may not precisely // represent the value that was entered by the user (for example, 0.1 // cannot be represented exactly by any finite binary fraction), the // scale may be much bigger than expected if the BigDecimal is created // directly from the double value (for example, with 0.1, the scale // would is 55). So we convert the double value to a string first, in // the hope that it will be reasonably rounded, and then convert that // string to a BigDecimal in order to get its scale. BigDecimal bd = new BigDecimal(Double.toString(value)); int scale = bd.scale(); // The value is constrained to 0..3 to prevent precisions that get too // large. return Math.max(0, Math.min(scale, 3)); } /** * Sets the orientation. * * @param horizontal * true for horizontal and false for vertical layout */ public void setOrientation(final boolean horizontal) { _scrollBar.setOrientation(horizontal ? Orientable.HORIZONTAL : Orientable.VERTICAL); } @Override public void setForegroundColor(final Color fg) { _scrollBar.setAlarmColor(fg); // super.setForegroundColor(fg); } @Override public void setBackgroundColor(final Color bg) { _scrollBar.setBackgroundColor(bg); // super.setForegroundColor(fg); } /** * Set the current slider value. * * <b>Important:</b> This method should only get called by the Controller and not by the figure * itself! * * @param value * the current slider value */ public void setValue(final double value) { _originalVal = value; // CentralLogger.getInstance().debug(this, "setValue("+value+")"); // // store current value // _currentValue = (int) (value * _scrollbarPrecision); // // // update scrollbar // if (_currentValue < _min || _currentValue > _max) { // // current value is out of the sliders range -> disable the slider // _scrollBar.setEnabled(false); // _scrollBar.setValue(_currentValue); // } else { // _scrollBar.setEnabled(true); // _scrollBar.setValue(_currentValue); // _scrollBar.invalidate(); // } updateScrollbar(); updateValueText(); } /** * Set the current manual value. * * <b>Important:</b> This method should only get called by the Controller and not by the figure * itself! * * @param value * the current slider value */ public void setManualValue(final double value) { _originalManVal = value; updateValueText(); } /** * Updates the value labels text. */ private void updateValueText() { // if (isEnabled()) { // update the value label text NumberFormat format = NumberFormat.getInstance(); format.setMaximumFractionDigits(_decimalPlaces); _valueLabel .setText("" + format.format(_originalVal) + " [MAN: " + format.format(_originalManVal) + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ // } } /** * Add a slider listener. * * @param listener * The slider listener to add. */ public void addSliderListener(final ISliderListener listener) { _sliderListeners.add(listener); } /** * Remove a slider listener. * * @param listener * The slider listener that is to be removed. */ public void removeSliderListener(final ISliderListener listener) { _sliderListeners.remove(listener); } /** * This method is a tribute to unit tests, which need a way to test the performance of the * figure implementation. Implementors should produce some random changes and refresh the * figure, when this method is called. * */ public void randomNoiseRefresh() { } /** * {@inheritDoc} */ @Override public void setEnabled(final boolean value) { _enable = value; _scrollBar.enableButtons(_enable); _scrollBar.setEnabled(true); super.setEnabled(value); } @Override protected void paintFigure(final Graphics graphics) { graphics.setBackgroundColor(getBackgroundColor()); bounds.crop(this.getInsets()); graphics.fillRectangle(bounds); graphics.setBackgroundColor(getBackgroundColor()); graphics.setForegroundColor(getForegroundColor()); } /** * {@inheritDoc} */ @Override public Object getAdapter(final Class adapter) { if (adapter == IBorderEquippedWidget.class) { if (_borderAdapter == null) { _borderAdapter = new BorderAdapter(this); } return _borderAdapter; } else if (adapter == ICrossedFigure.class) { if (_crossedOutAdapter == null) { _crossedOutAdapter = new CrossedOutAdapter(this); } return _crossedOutAdapter; } else if (adapter == IRhombusEquippedWidget.class) { if (_rhombusAdapter == null) { _rhombusAdapter = new RhombusAdapter(this); } return _rhombusAdapter; } return null; } /** * Definition of listeners that react on slider events. * * @author Sven Wende * @version $Revision: 1.30 $ * */ public interface ISliderListener { /** * React on a slider event. * * @param newValue * The new slider value. */ void sliderValueChanged(double newValue); } /** * * A Scrollbar how can disable separately the Buttons * * @author hrickens * @author $Author: jhatje $ * @version $Revision: 1.30 $ * @since 16.04.2010 */ private class MyScrollBar extends ScrollBar{ public void enableButtons(final boolean enable) { getButtonUp().setEnabled(enable); if(enable) { getThumb().setBackgroundColor(new Color(null, 25,25,25)); } else { getThumb().setBackgroundColor(new Color(null, 155,155,155)); } getButtonDown().setEnabled(enable); } public void setAlarmColor(final Color color) { getButtonDown().setBackgroundColor(color); getButtonUp().setBackgroundColor(color); } } }