Commit 5f54ee0c authored by Evan W. Patton's avatar Evan W. Patton Committed by Susan Rati Lane

Implement scale bar for Map

Change-Id: I8824cde5d7481a6349e7604dd97a372b67abc7dc
parent 4ea8699e
......@@ -6655,6 +6655,10 @@ public interface OdeMessages extends Messages {
@Description("Show a compass control on the Map")
String ShowCompassProperties();
@DefaultMessage("ShowScale")
@Description("Show a scale indicator on the Map")
String ShowScaleProperties();
@DefaultMessage("ShowUser")
@Description("Show a marker on the Map for the user's current location")
String ShowUserProperties();
......
......@@ -32,6 +32,7 @@ public final class MockMap extends MockContainer {
protected static final String PROPERTY_NAME_SHOW_ZOOM = "ShowZoom";
protected static final String PROPERTY_NAME_SHOW_USER = "ShowUser";
protected static final String PROPERTY_NAME_ENABLE_ROTATION = "EnableRotation";
protected static final String PROPERTY_NAME_SHOW_SCALE = "ShowScale";
/**
* The Widget wrapping the element where the map tiles will be rendered.
......@@ -66,6 +67,7 @@ public final class MockMap extends MockContainer {
private boolean zoomControl = false;
private boolean compassEnabled = false;
private boolean userLocationEnabled = false;
private boolean showScale = false;
public MockMap(SimpleEditor editor) {
super(editor, TYPE, images.map(), new MockMapLayout());
......@@ -169,6 +171,8 @@ public final class MockMap extends MockContainer {
setShowUser(newValue);
} else if (propertyName.equals(PROPERTY_NAME_SHOW_ZOOM)) {
setShowZoom(newValue);
} else if (propertyName.equals(PROPERTY_NAME_SHOW_SCALE)) {
setShowScale(newValue);
}
}
......@@ -234,6 +238,11 @@ public final class MockMap extends MockContainer {
updateMapZoomControl(this.zoomControl);
}
private void setShowScale(String state) {
this.showScale = Boolean.parseBoolean(state);
updateMapShowScale(this.showScale);
}
// event handlers
protected void onBoundsChanged() {
// TODO(ewpatton): Send incremental update to companion
......@@ -459,7 +468,8 @@ public final class MockMap extends MockContainer {
var latitude = this.@com.google.appinventor.client.editor.simple.components.MockMap::latitude,
longitude = this.@com.google.appinventor.client.editor.simple.components.MockMap::longitude,
zoomControl = this.@com.google.appinventor.client.editor.simple.components.MockMap::zoomControl,
zoom = this.@com.google.appinventor.client.editor.simple.components.MockMap::zoomLevel;
zoom = this.@com.google.appinventor.client.editor.simple.components.MockMap::zoomLevel,
showScale = this.@com.google.appinventor.client.editor.simple.components.MockMap::showScale;
map = L.map(elem, {zoomControl: false, editable: true}).setView([latitude, longitude], zoom);
var messages = @com.google.appinventor.client.Ode::getMessages()();
map.zoomControl = L.control.zoom({
......@@ -470,6 +480,10 @@ public final class MockMap extends MockContainer {
if (zoomControl) {
map.zoomControl.addTo(map);
}
map.scaleControl = L.control.scale({position: 'bottomright'});
if (showScale) {
map.scaleControl.addTo(map);
}
map.owner = this;
map.unlocked = true;
map.aiControls = new L.Toolbar.Control({position: 'bottomleft',
......@@ -604,6 +618,20 @@ public final class MockMap extends MockContainer {
}
}-*/;
private native void updateMapShowScale(boolean enable)/*-{
var map = this.@com.google.appinventor.client.editor.simple.components.MockMap::mapInstance;
if (map) {
if (!map.scaleControl) {
map.scaleControl = $wnd.top.L.control.scale({position: 'topleft'});
}
if (enable) {
map.scaleControl.addTo(map);
} else {
map.removeControl(map.scaleControl);
}
}
}-*/;
private native boolean isUnlocked()/*-{
var map = this.@com.google.appinventor.client.editor.simple.components.MockMap::mapInstance;
if (map) {
......
......@@ -879,7 +879,9 @@ public class YaVersion {
// - GeoJSONError was renamed to LoadError
// For MAP_COMPONENT_VERSION 4:
// - Added Rotation property
public static final int MAP_COMPONENT_VERSION = 4;
// For MAP_COMPONENT_VERSION 5:
// - Added Scale property
public static final int MAP_COMPONENT_VERSION = 5;
// For MARKER_COMPONENT_VERSION 1:
// - Initial Marker implementation using OpenStreetMap
......
......@@ -114,6 +114,7 @@ public class Map extends MapFeatureContainerBase implements MapEventListener {
ShowUser(false);
ShowZoom(false);
EnableRotation(false);
ShowScale(false);
}
@Override
......@@ -449,6 +450,18 @@ public class Map extends MapFeatureContainerBase implements MapEventListener {
return sensor;
}
@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN, defaultValue = "False")
@SimpleProperty
public void ShowScale(boolean show) {
mapController.setScaleVisible(show);
}
@SimpleProperty(category = PropertyCategory.BEHAVIOR,
description = "Shows a scale reference on the map.")
public boolean ShowScale() {
return mapController.isScaleVisible();
}
@SimpleProperty(category = PropertyCategory.BEHAVIOR,
description = "Returns the user's latitude if ShowUser is enabled.")
public double UserLatitude() {
......
......@@ -257,4 +257,14 @@ class DummyMapController implements MapController {
public int getOverlayCount() {
throw new UnsupportedOperationException();
}
@Override
public void setScaleVisible(boolean show) {
throw new UnsupportedOperationException();
}
@Override
public boolean isScaleVisible() {
throw new UnsupportedOperationException();
}
}
......@@ -524,6 +524,20 @@ public final class MapFactory {
* @return the rotation
*/
float getRotation();
/**
* Sets whether or not the scale overlay is visible.
* @param show True if the scale should be shown, otherwise false.
*/
void setScaleVisible(boolean show);
/**
* Gets the visibility of the scale on the map. A true value does
* not guarantee that the scale is visible to the user (i.e., if
* the Map is not visible).
* @returns true if the scale is enabled on the map, otherwise false.
*/
boolean isScaleVisible();
}
/**
......
......@@ -61,6 +61,7 @@ import org.osmdroid.views.overlay.OverlayWithIW;
import org.osmdroid.views.overlay.OverlayWithIWVisitor;
import org.osmdroid.views.overlay.Polygon;
import org.osmdroid.views.overlay.Polyline;
import org.osmdroid.views.overlay.ScaleBarOverlay;
import org.osmdroid.views.overlay.compass.CompassOverlay;
import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider;
import org.osmdroid.views.overlay.gestures.RotationGestureOverlay;
......@@ -109,6 +110,7 @@ class NativeOpenStreetMapController implements MapController, MapListener {
private boolean ready = false;
private ZoomControlView zoomControls = null;
private float lastAzimuth = Float.NaN;
private ScaleBarOverlay scaleBar;
private static class AppInventorLocationSensorAdapter implements IMyLocationProvider,
LocationSensor.LocationSensorListener {
......@@ -293,6 +295,11 @@ class NativeOpenStreetMapController implements MapController, MapListener {
});
zoomControls = new ZoomControlView(view);
userLocation = new MyLocationNewOverlay(locationProvider, view);
scaleBar = new ScaleBarOverlay(view);
scaleBar.setAlignBottom(true);
scaleBar.setAlignRight(true);
scaleBar.disableScaleBar();
view.getOverlayManager().add(scaleBar);
containerView = new RelativeLayout(form);
containerView.setClipChildren(true);
......@@ -1212,6 +1219,17 @@ class NativeOpenStreetMapController implements MapController, MapListener {
return view.getMapOrientation();
}
@Override
public void setScaleVisible(boolean show) {
scaleBar.setEnabled(show);
view.invalidate();
}
@Override
public boolean isScaleVisible() {
return scaleBar.isEnabled();
}
static class MultiPolygon extends Polygon {
private List<Polygon> children = new ArrayList<Polygon>();
......
......@@ -7,6 +7,8 @@ package com.google.appinventor.components.runtime;
import android.content.Context;
import android.hardware.Sensor;
import android.view.View;
import android.widget.RelativeLayout;
import com.google.appinventor.components.runtime.shadows.ShadowAsynchUtil;
import com.google.appinventor.components.runtime.util.ErrorMessages;
import com.google.appinventor.components.runtime.util.GeometryUtil;
......@@ -15,6 +17,7 @@ import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapView;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowSensorManager;
......@@ -147,6 +150,20 @@ public class MapTest extends MapTestBase {
assertTrue(map.ShowUser());
}
/**
* Test that:
* !) Showing the scale invalidates the view
* 2) if we show the scale, the ShowScale getter will return true.
*/
@Test
public void testShowScale() {
shadowOf(getMapView()).clearWasInvalidated();
map.ShowScale(true);
// Make sure that the view was invalidated
assertTrue(shadowOf(getMapView()).wasInvalidated());
assertTrue(map.ShowScale());
}
@Test
public void testLocationSensor() {
LocationSensor sensor = new LocationSensor(getForm());
......@@ -341,9 +358,20 @@ public class MapTest extends MapTestBase {
*/
@Test
public void testResetFeatureList() {
int defaultFeatureListSize = map.getController().getOverlayCount();
new Marker(map);
assertEquals(defaultFeatureListSize + 1, map.getController().getOverlayCount());
map.Features(YailList.makeEmptyList());
assertEquals(0, map.Features().size());
assertEquals(1, map.getController().getOverlayCount());
assertEquals(defaultFeatureListSize, map.getController().getOverlayCount());
}
private MapView getMapView() {
RelativeLayout layout = (RelativeLayout) map.getView();
return (MapView) layout.getChildAt(0);
}
private static ShadowView shadowOf(View view) {
return (ShadowView) Shadow.extract(view);
}
}
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