Commit 43d46d20 authored by kkashi's avatar kkashi Committed by Gerrit Review System

Added Slider visible component. A Slider is like a ProgressBar that adds

a draggable thumb. You can touch the thumb and drag left or right to set the
current slider position. This triggers PositionChanged, reporting current
position of the slider thumb.
The slider has min, max and initialPosition properties.
The reported thumb position can be used to dynamically change another
component property; such as TextBox font size or Ball radius.

Change-Id: I30d6714c3b6307776c6b211ae8797cd0c81edec8
parent c0451fb2
......@@ -265,6 +265,12 @@ public interface Images extends Resources {
@Source("com/google/appinventor/images/ball.png")
ImageResource ball();
/**
* Designer palette item: Slider
*/
@Source("com/google/appinventor/images/slider.png")
ImageResource slider();
/**
* Designer palette item: Notifier
*/
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the MIT License https://raw.github.com/mit-cml/app-inventor/master/mitlicense.txt
package com.google.appinventor.client.editor.simple.components;
import com.google.appinventor.client.editor.simple.SimpleEditor;
import com.google.gwt.user.client.ui.SimplePanel;
/**
* Mock Slider component.
*
* @author M. Hossein Amerkashi - kkashi01@gmail.com
*/
public final class MockSlider extends MockVisibleComponent {
/**
* Component type name.
*/
public static final String TYPE = "Slider";
private static final int DEFAULT_WIDTH = 70;
// Widget for showing the mock slider
private final SimplePanel sliderWidget;
/**
* Creates a new MockSlider component.
*
* @param editor editor of source file the component belongs to
*/
public MockSlider(SimpleEditor editor) {
super(editor, TYPE, images.slider());
// Initialize mock slider UI
sliderWidget = new SimplePanel();
sliderWidget.setStylePrimaryName("ode-SimpleMockComponent");
sliderWidget.setWidget(getIconImage());
initComponent(sliderWidget);
}
@Override
protected boolean isPropertyVisible(String propertyName) {
//We don't want to allow user to change the slider height. S/he can only change the
//slider width
if (propertyName.equals(PROPERTY_NAME_HEIGHT)) {
return false;
}
return super.isPropertyVisible(propertyName);
}
@Override
public int getPreferredWidth() {
// The superclass uses getOffsetWidth, which won't work for us.
return DEFAULT_WIDTH;
}
// PropertyChangeListener implementation
@Override
public void onPropertyChange(String propertyName, String newValue) {
super.onPropertyChange(propertyName, newValue);
}
}
......@@ -26,6 +26,7 @@ import com.google.appinventor.client.editor.simple.components.MockNonVisibleComp
import com.google.appinventor.client.editor.simple.components.MockPasswordTextBox;
import com.google.appinventor.client.editor.simple.components.MockPhoneNumberPicker;
import com.google.appinventor.client.editor.simple.components.MockRadioButton;
import com.google.appinventor.client.editor.simple.components.MockSlider;
import com.google.appinventor.client.editor.simple.components.MockTableArrangement;
import com.google.appinventor.client.editor.simple.components.MockTextBox;
import com.google.appinventor.client.editor.simple.components.MockVerticalArrangement;
......@@ -254,6 +255,8 @@ public final class SimpleComponentDescriptor {
return new MockImage(editor);
} else if (name.equals(MockLabel.TYPE)) {
return new MockLabel(editor);
} else if (name.equals(MockSlider.TYPE)) {
return new MockSlider(editor);
} else if (name.equals(MockPasswordTextBox.TYPE)) {
return new MockPasswordTextBox(editor);
} else if (name.equals(MockRadioButton.TYPE)) {
......
......@@ -213,6 +213,9 @@ public final class YoungAndroidFormUpgrader {
} else if (componentType.equals("BluetoothServer")) {
srcCompVersion = upgradeBluetoothServerProperties(componentProperties, srcCompVersion);
} else if (componentType.equals("Slider")) {
srcCompVersion = upgradeSliderProperties(componentProperties, srcCompVersion);
} else if (componentType.equals("Button")) {
srcCompVersion = upgradeButtonProperties(componentProperties, srcCompVersion);
......@@ -452,6 +455,15 @@ public final class YoungAndroidFormUpgrader {
}
return srcCompVersion;
}
private static int upgradeSliderProperties(Map<String, JSONValue> componentProperties,
int srcCompVersion) {
if (srcCompVersion < 1) {
// Initial version. Placeholder for future upgrades
srcCompVersion = 1;
}
return srcCompVersion;
}
private static int upgradeButtonProperties(Map<String, JSONValue> componentProperties,
int srcCompVersion) {
......
......@@ -401,6 +401,9 @@ public class BlockSaveFile {
} else if (genus.equals("BluetoothServer")) {
blkCompVersion = upgradeBluetoothServerBlocks(blkCompVersion, componentName);
} else if (genus.equals("Slider")) {
blkCompVersion = upgradeSliderBlocks(blkCompVersion, componentName);
} else if (genus.equals("Button")) {
blkCompVersion = upgradeButtonBlocks(blkCompVersion, componentName);
......@@ -677,6 +680,15 @@ public class BlockSaveFile {
return blkCompVersion;
}
private int upgradeSliderBlocks(int blkCompVersion, String componentName) {
if (blkCompVersion < 1) {
//This is initial version. Placeholder for future upgrades
blkCompVersion = 1;
}
return blkCompVersion;
}
private int upgradeCanvasBlocks(int blkCompVersion, String componentName) {
if (blkCompVersion < 2) {
// The LineWidth property was added.
......
......@@ -217,7 +217,9 @@ public class YaVersion {
// - WEBVIEWER_COMPONENT_VERSION was incremented to 3
// For YOUNG_ANDROID_VERSION 73:
// - BUTTON_COMPONENT_VERSION was incremented to 5.
public static final int YOUNG_ANDROID_VERSION = 73;
// For YOUNG_ANDROID_VERSION 74:
// - SLIDER_COMPONENT_VERSION was incremented to 1.
public static final int YOUNG_ANDROID_VERSION = 74;
// ............................... Blocks Language Version Number ...............................
......@@ -609,4 +611,8 @@ public class YaVersion {
// - Add UsesLocation property to set location permissions
public static final int WEBVIEWER_COMPONENT_VERSION = 3;
// For SLIDER_COMPONENT_VERSION 1:
// - Initial version.
public static final int SLIDER_COMPONENT_VERSION = 1;
}
......@@ -112,4 +112,10 @@ public interface Component {
static final int DIRECTION_NONE = 0;
static final int DIRECTION_MIN = -4;
static final int DIRECTION_MAX = 4;
//Slider defaults for setting Min value, Max Value and the position of the Slider thumb
public static float SLIDER_MIN_VALUE=10;
public static float SLIDER_MAX_VALUE=40;
public static float SLIDER_THUMB_VALUE=20;
}
package com.google.appinventor.components.runtime;
import android.util.Log;
import android.view.View;
import android.widget.SeekBar;
import com.google.appinventor.components.annotations.DesignerComponent;
import com.google.appinventor.components.annotations.DesignerProperty;
import com.google.appinventor.components.annotations.PropertyCategory;
import com.google.appinventor.components.annotations.SimpleEvent;
import com.google.appinventor.components.annotations.SimpleObject;
import com.google.appinventor.components.annotations.SimpleProperty;
import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.common.PropertyTypeConstants;
import com.google.appinventor.components.common.YaVersion;
/**
* This class is used to display a Slider.
* <p>The Slider is like a ProgressBar that adds a draggable thumb. You can touch the thumb and drag
* left or right to set the slider thumb position. As Slider thumb is dragged, it will trigger
* PositionChanged event, reporting the position of the Slider thumb. The Slider uses the following
* default values. However these values can be changed through designer or block editor
* <ul>
* <li>MinValue</li>
* <li>MaxValue</li>
* <li>ThumbPosition</li>
* </ul></p>
*
* @author M. Hossein Amerkashi
*/
@DesignerComponent(version = YaVersion.SLIDER_COMPONENT_VERSION,
description = "A Slider is like a ProgressBar that adds a draggable thumb. You can touch " +
"the thumb and drag left or right to set the slider thumb position. " +
"As Slider thumb is dragged, it will trigger PositionChanged event, " +
"reporting the position of the Slider thumb. The reported position of the " +
"Slider thumb can be used to dynamically update another component " +
"attribute, such as a TextBox font size or a Ball component radius.",
category = ComponentCategory.BASIC)
@SimpleObject
public class Slider extends AndroidViewComponent implements SeekBar.OnSeekBarChangeListener {
private final static String LOG_TAG = "Slider";
private final SeekBar view;
float sliderMinValue;
float sliderMaxValue;
float sliderThumbPosition;
/**
* Creates a new Slider component.
*
* @param container container that the component will be placed in
*/
public Slider(ComponentContainer container) {
super(container);
view = new SeekBar(container.$context());
// Adds the component to its designated container
container.$add(this);
// Default property values. Don't use MinValue() or MaxValue() or ThumbPosition()
sliderMinValue = Component.SLIDER_MIN_VALUE;
sliderMaxValue = Component.SLIDER_MAX_VALUE;
sliderThumbPosition = Component.SLIDER_THUMB_VALUE;
view.setOnSeekBarChangeListener(this);
//NOTE: The boundaries for Seekbar are between 0-100 and there is no lower-limit that could
// be set. We use math to calculate the lower / upper / thumb position.
// keep the SeekBar effectively at [0-100] and calculate thumb position within that range
view.setMax(100);
//Based on given min, max & thumb position, determine where the thumb position would be
// within normal SeekBar 0-100 range
recalcThumbPosition(sliderMinValue, sliderMaxValue, sliderThumbPosition);
Log.d(LOG_TAG, "Slider initial min, max, thumb values are: " +
MinValue() + "/" + MaxValue() + "/" + ThumbPosition());
}
/**
* Given min, max, thumb position, this method determines where the thumb position would be
* within normal SeekBar 0-100 range
*
* @param min value for slider
* @param max value for slider
* @param thumb the slider thumb position
*/
private void recalcThumbPosition(float min, float max, float thumb) {
//Based on given min, max & thumb position, determine where it falls in range of 0-100
float calc = ((thumb - min) / (max - min)) * 100;
Log.d(LOG_TAG, "Trying to recalculate. min, max, thumb, recalculatedValue: "
+ min + "/" + max + "/" + thumb + "/" + calc);
sliderThumbPosition = calc;
//Now set the thumb position on progress bar
view.setProgress((int) calc);
}
/**
* Sets the slider thumb position.
*
* @param position the position of the slider thumb. This value should be between
* sliderMinValue and sliderMaxValue. If this value is not within the min and
* max, then it will be calculated.
*/
@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_FLOAT,
defaultValue = Component.SLIDER_THUMB_VALUE + "")
@SimpleProperty(description = "Specifies the position of the slider thumb. " +
"If this value is > MaxValue, then it will be set to same value as MaxValue. " +
"If this value is < MinValue, then it will be set to same value as MinValue.",
userVisible = true)
public void ThumbPosition(float position) {
sliderThumbPosition = position;
Log.d(LOG_TAG, "ThumbPosition is set to: " + sliderThumbPosition);
recalcThumbPosition(sliderMinValue, sliderMaxValue, sliderThumbPosition);
}
/**
* Returns the position of slider thumb
*
* @return the slider thumb position
*/
@SimpleProperty(category = PropertyCategory.APPEARANCE,
description = "Returns the position of slider thumb", userVisible = true)
public float ThumbPosition() {
return sliderThumbPosition;
}
@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_FLOAT,
defaultValue = Component.SLIDER_MIN_VALUE + "")
@SimpleProperty(description = "Specifies the min value of slider. If this value is > slider " +
"ThumbPosition, then it will be set to same value as ThumbPosition.", userVisible = true)
public void MinValue(float minValue) {
Log.d(LOG_TAG, "Min value is set to: " + minValue);
sliderMinValue = minValue;
recalcThumbPosition(minValue, sliderMaxValue, sliderThumbPosition);
}
/**
* Returns the value of slider min value.
*
* @return the value of slider min value.
*/
@SimpleProperty(category = PropertyCategory.APPEARANCE,
description = "Returns the value of slider min value.", userVisible = true)
public float MinValue() {
return sliderMinValue;
}
@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_FLOAT,
defaultValue = Component.SLIDER_MAX_VALUE + "")
@SimpleProperty(description = "Specifies the max value of slider. " +
"If this value is < ThumbPosition, then it will be set to same value as ThumbPosition",
userVisible = true)
public void MaxValue(float maxValue) {
Log.d(LOG_TAG, "Max value is set to: " + maxValue);
sliderMaxValue = maxValue;
recalcThumbPosition(sliderMinValue, maxValue, sliderThumbPosition);
}
/**
* Returns the slider max value
*
* @return the slider max value
*/
@SimpleProperty(category = PropertyCategory.APPEARANCE,
description = "Returns the slider max value.", userVisible = true)
public float MaxValue() {
return sliderMaxValue;
}
@Override
public View getView() {
return view;
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
//progress has been changed. Set the sliderThumbPosition and then trigger the event
//Now convert this progress value (which is between 0-100), back to a value between the
//range that user has set within min, max
sliderThumbPosition = ((sliderMaxValue - sliderMinValue) * (float) progress / 100)
+ sliderMinValue;
Log.d(LOG_TAG, "onProgressChanged progress value [0-100]: " + progress
+ ", reporting to user as: " + sliderThumbPosition);
//Trigger the event, reporting this new value
PositionChanged(sliderThumbPosition);
}
/**
* Indicates that position of the slider thumb has changed.
*/
@SimpleEvent
public void PositionChanged(float thumbPosition) {
EventDispatcher.dispatchEvent(this, "PositionChanged", thumbPosition);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
/**
* Returns the component's vertical height, measured in pixels.
*
* @return height in pixels
*/
@Override
public int Height() {
//NOTE: overriding and removing the annotation, because we don't want to give user
//ability to change the slider height and don't want display this in our block editor
return getView().getHeight();
}
/**
* Specifies the component's vertical height, measured in pixels.
*
* @param height in pixels
*/
@Override
public void Height(int height) {
//NOTE: overriding and removing the annotation, because we don't want to give user
//ability to change the slider height and don't want display this in our block editor
container.setChildHeight(this, height);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment