diff --git a/apps/tests/ui/view/view-tests-common.ts b/apps/tests/ui/view/view-tests-common.ts index 61f1f19ce..5a70d3b9b 100644 --- a/apps/tests/ui/view/view-tests-common.ts +++ b/apps/tests/ui/view/view-tests-common.ts @@ -3,7 +3,7 @@ import viewModule = require("ui/core/view"); import frame = require("ui/frame"); import page = require("ui/page"); import button = require("ui/button"); -import label = require("ui/label"); +import labelModule = require("ui/label"); import types = require("utils/types"); import helper = require("../../ui/helper"); import color = require("color"); @@ -14,6 +14,7 @@ import observable = require("data/observable"); import bindable = require("ui/core/bindable"); import definition = require("./view-tests"); import enums = require("ui/enums"); +import absoluteLayoutModule = require("ui/layouts/absolute-layout"); export var test_eachDescendant = function () { var test = function (views: Array) { @@ -625,7 +626,7 @@ export var test_binding_style_opacity = function () { } function _createLabelWithBorder(): viewModule.View { - var lbl = new label.Label(); + var lbl = new labelModule.Label(); lbl.borderRadius = 10; lbl.borderWidth = 2; lbl.borderColor = new color.Color("#FF0000"); @@ -635,7 +636,7 @@ function _createLabelWithBorder(): viewModule.View { } export var testIsVisible = function () { - var lbl = new label.Label(); + var lbl = new labelModule.Label(); helper.buildUIAndRunTest(lbl, function (views: Array) { TKUnit.assertEqual(lbl.visibility, enums.Visibility.visible); @@ -652,7 +653,7 @@ export var testIsVisible = function () { } export var testSetInlineStyle = function () { - var lbl = new label.Label(); + var lbl = new labelModule.Label(); var expectedColor = "#ff0000"; var expectedBackgroundColor = "#ff0000"; @@ -667,7 +668,7 @@ export var testSetInlineStyle = function () { export var testBorderWidth = function () { helper.buildUIAndRunTest(_createLabelWithBorder(), function (views: Array) { - var lbl = views[0]; + var lbl = views[0]; var expectedValue = lbl.borderWidth; var actualValue = definition.getNativeBorderWidth(lbl); TKUnit.assertEqual(actualValue, expectedValue); @@ -676,7 +677,7 @@ export var testBorderWidth = function () { export var testCornerRadius = function () { helper.buildUIAndRunTest(_createLabelWithBorder(), function (views: Array) { - var lbl = views[0]; + var lbl = views[0]; var expectedValue = lbl.borderRadius; var actualValue = definition.getNativeCornerRadius(lbl); TKUnit.assertEqual(actualValue, expectedValue); @@ -685,14 +686,14 @@ export var testCornerRadius = function () { export var testBorderColor = function () { helper.buildUIAndRunTest(_createLabelWithBorder(), function (views: Array) { - var lbl = views[0]; + var lbl = views[0]; TKUnit.assertEqual(definition.checkNativeBorderColor(lbl), true, "BorderColor not applied correctly!"); }); } export var testBackgroundColor = function () { helper.buildUIAndRunTest(_createLabelWithBorder(), function (views: Array) { - var lbl = views[0]; + var lbl = views[0]; TKUnit.assertEqual(definition.checkNativeBackgroundColor(lbl), true, "BackgroundColor not applied correctly!"); }); } @@ -710,4 +711,72 @@ export var testBackgroundImage = function () { export function test_automation_text_default_value() { let view = new button.Button(); TKUnit.assertTrue(view.automationText === undefined, "AutomationText default value should be UNDEFINED."); +} + +export var test_getLocationInWindow_IsUndefinedWhenNotInTheVisualTree = function () { + var label = new labelModule.Label(); + TKUnit.assertNull(label.getLocationInWindow()); +} + +export var test_getLocationOnScreen_IsUndefinedWhenNotInTheVisualTree = function () { + var label = new labelModule.Label(); + TKUnit.assertNull(label.getLocationOnScreen()); +} + +var delta = 0.1; +export var test_getLocationRelativeToOtherView = function () { + var a1 = new absoluteLayoutModule.AbsoluteLayout(); + a1.width = 200; + a1.height = 200; + a1.backgroundColor = new color.Color("red"); + + var a2 = new absoluteLayoutModule.AbsoluteLayout(); + a2.width = 100; + a2.height = 100; + absoluteLayoutModule.AbsoluteLayout.setLeft(a2, 11); + absoluteLayoutModule.AbsoluteLayout.setTop(a2, 12); + a2.backgroundColor = new color.Color("green"); + + var label = new labelModule.Label(); + label.text = "label"; + label.id = "label"; + label.width = 70; + label.height = 30; + absoluteLayoutModule.AbsoluteLayout.setLeft(label, 13); + absoluteLayoutModule.AbsoluteLayout.setTop(label, 14); + a2.backgroundColor = new color.Color("yellow"); + + a2.addChild(label); + a1.addChild(a2); + + helper.buildUIAndRunTest(a1, function (views: Array) { + frame.topmost().requestLayout(); + TKUnit.wait(0.1); + + var labelInA2 = label.getLocationRelativeTo(a2); + var labelInA1 = label.getLocationRelativeTo(a1); + var a2InA1 = a2.getLocationRelativeTo(a1); + + TKUnit.assertAreClose(labelInA2.x, 13, delta); + TKUnit.assertAreClose(labelInA2.y, 14, delta); + + TKUnit.assertAreClose(labelInA1.x, 24, delta); + TKUnit.assertAreClose(labelInA1.y, 26, delta); + + TKUnit.assertAreClose(a2InA1.x, 11, delta); + TKUnit.assertAreClose(a2InA1.y, 12, delta); + }); +} + +export var test_getActualSize = function () { + var label = new labelModule.Label(); + label.width = 100; + label.height = 200; + helper.buildUIAndRunTest(label, function (views: Array) { + frame.topmost().requestLayout(); + TKUnit.wait(0.1); + var actualSize = label.getActualSize(); + TKUnit.assertAreClose(actualSize.width, 100, delta); + TKUnit.assertAreClose(actualSize.height, 200, delta); + }); } \ No newline at end of file diff --git a/ui/core/view-common.ts b/ui/core/view-common.ts index d812361aa..9d15cc10b 100644 --- a/ui/core/view-common.ts +++ b/ui/core/view-common.ts @@ -1140,6 +1140,39 @@ export class View extends ProxyObject implements definition.View { return undefined; } + public getLocationInWindow(): definition.Point { + return undefined; + } + + public getLocationOnScreen(): definition.Point { + return undefined; + } + + public getLocationRelativeTo(otherView: definition.View): definition.Point { + var my = this.getLocationInWindow(); + var other = otherView.getLocationInWindow(); + if (!my || !other) { + return undefined; + } + + return { + x: my.x - other.x, + y: my.y - other.y + } + } + + public getActualSize(): definition.Size { + var currentBounds = this._getCurrentLayoutBounds(); + if (!currentBounds) { + return undefined; + } + + return { + width: utils.layout.toDeviceIndependentPixels(currentBounds.right - currentBounds.left), + height: utils.layout.toDeviceIndependentPixels(currentBounds.bottom - currentBounds.top), + } + } + public animate(animation: any): Promise { return this.createAnimation(animation).play(); } diff --git a/ui/core/view.android.ts b/ui/core/view.android.ts index 4002efbab..93b13caea 100644 --- a/ui/core/view.android.ts +++ b/ui/core/view.android.ts @@ -363,6 +363,32 @@ export class View extends viewCommon.View { return false; } + public getLocationInWindow(): viewDefinition.Point { + if (!this._nativeView || !this._nativeView.getWindowToken()) { + return undefined; + } + + var nativeArray = (Array).create("int", 2); + this._nativeView.getLocationInWindow(nativeArray); + return { + x: utils.layout.toDeviceIndependentPixels(nativeArray[0]), + y: utils.layout.toDeviceIndependentPixels(nativeArray[1]), + } + } + + public getLocationOnScreen(): viewDefinition.Point { + if (!this._nativeView || !this._nativeView.getWindowToken()) { + return undefined; + } + + var nativeArray = (Array).create("int", 2); + this._nativeView.getLocationOnScreen(nativeArray); + return { + x: utils.layout.toDeviceIndependentPixels(nativeArray[0]), + y: utils.layout.toDeviceIndependentPixels(nativeArray[1]), + } + } + public static resolveSizeAndState(size: number, specSize: number, specMode: number, childMeasuredState: number): number { var result = size; switch (specMode) { diff --git a/ui/core/view.d.ts b/ui/core/view.d.ts index c7da2cc7e..db4911afe 100644 --- a/ui/core/view.d.ts +++ b/ui/core/view.d.ts @@ -32,6 +32,38 @@ declare module "ui/core/view" { export function isEventOrGesture(name: string, view: View): boolean; + /** + * The Point interface describes a two dimensional location. + * It has two properties x and y, representing the x and y coordinate of the location. + */ + export interface Point { + /** + * Represents the x coordinate of the location. + */ + x: number; + + /** + * Represents the y coordinate of the location. + */ + y: number; + } + + /** + * The Size interface describes abstract dimensions in two dimensional space. + * It has two properties width and height, representing the width and height values of the size. + */ + export interface Size { + /** + * Represents the width of the size. + */ + width: number; + + /** + * Represents the height of the size. + */ + height: number; + } + /** * Defines interface for an optional parameter used to create a view. */ @@ -433,7 +465,7 @@ declare module "ui/core/view" { /** * Returns the child view with the specified id. */ - getViewById(id: string): T; + public getViewById(id: string): T; /** * Tries to focus the view. @@ -483,9 +515,36 @@ declare module "ui/core/view" { */ on(event: "unloaded", callback: (args: observable.EventData) => void, thisArg?: any); + /** + * Animates one or more properties of the view based on the supplied options. + */ public animate(options: animation.AnimationDefinition): Promise; + + /** + * Creates an Animation object based on the supplied options. + */ public createAnimation(options: animation.AnimationDefinition): animation.Animation; + /** + * Returns the location of this view in the window coordinate system. + */ + public getLocationInWindow(): Point; + + /** + * Returns the location of this view in the screen coordinate system. + */ + public getLocationOnScreen(): Point; + + /** + * Returns the location of this view in the otherView's coordinate system. + */ + public getLocationRelativeTo(otherView: View): Point; + + /** + * Returns the actual size of the view in device-independent pixels. + */ + public getActualSize(): Size; + // Lifecycle events onLoaded(): void; onUnloaded(): void; diff --git a/ui/core/view.ios.ts b/ui/core/view.ios.ts index dd1754b09..6c411913e 100644 --- a/ui/core/view.ios.ts +++ b/ui/core/view.ios.ts @@ -1,5 +1,6 @@ import types = require("utils/types"); import viewCommon = require("./view-common"); +import viewDefinition = require("ui/core/view"); import trace = require("trace"); import utils = require("utils/utils"); import dependencyObservable = require("ui/core/dependency-observable"); @@ -252,6 +253,31 @@ export class View extends viewCommon.View { return false; } + public getLocationInWindow(): viewDefinition.Point { + if (!this._nativeView || !this._nativeView.window) { + return undefined; + } + + var pointInWindow = this._nativeView.convertPointToView(this._nativeView.bounds.origin, null); + return { + x: utils.layout.toDeviceIndependentPixels(pointInWindow.x), + y: utils.layout.toDeviceIndependentPixels(pointInWindow.y), + } + } + + public getLocationOnScreen(): viewDefinition.Point { + if (!this._nativeView || !this._nativeView.window) { + return undefined; + } + + var pointInWindow = this._nativeView.convertPointToView(this._nativeView.bounds.origin, null); + var pointOnScreen = this._nativeView.window.convertPointToWindow(pointInWindow, null); + return { + x: utils.layout.toDeviceIndependentPixels(pointOnScreen.x), + y: utils.layout.toDeviceIndependentPixels(pointOnScreen.y), + } + } + private _onSizeChanged() { this.style._sizeChanged(); }