/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.flat;
import javax.annotation.Nullable;
import android.graphics.Rect;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.Spacing;
import com.facebook.react.uimanager.ReactStylesDiffMap;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.annotations.ReactPropGroup;
/**
* Node for a react View.
*/
/* package */ final class RCTView extends FlatShadowNode {
private static final int[] SPACING_TYPES = {
Spacing.ALL, Spacing.LEFT, Spacing.RIGHT, Spacing.TOP, Spacing.BOTTOM,
};
private @Nullable DrawBorder mDrawBorder;
boolean mRemoveClippedSubviews;
boolean mHorizontal;
private @Nullable Rect mHitSlop;
@Override
/* package */ void handleUpdateProperties(ReactStylesDiffMap styles) {
mRemoveClippedSubviews = mRemoveClippedSubviews ||
(styles.hasKey(PROP_REMOVE_CLIPPED_SUBVIEWS) &&
styles.getBoolean(PROP_REMOVE_CLIPPED_SUBVIEWS, false));
if (mRemoveClippedSubviews) {
mHorizontal = mHorizontal ||
(styles.hasKey(PROP_HORIZONTAL) && styles.getBoolean(PROP_HORIZONTAL, false));
}
super.handleUpdateProperties(styles);
}
@Override
protected void collectState(
StateBuilder stateBuilder,
float left,
float top,
float right,
float bottom,
float clipLeft,
float clipTop,
float clipRight,
float clipBottom) {
super.collectState(
stateBuilder,
left,
top,
right,
bottom,
clipLeft,
clipTop,
clipRight,
clipBottom);
if (mDrawBorder != null) {
mDrawBorder = (DrawBorder) mDrawBorder.updateBoundsAndFreeze(
left,
top,
right,
bottom,
clipLeft,
clipTop,
clipRight,
clipBottom);
stateBuilder.addDrawCommand(mDrawBorder);
}
}
@Override
boolean doesDraw() {
return mDrawBorder != null || super.doesDraw();
}
@Override
public void setBackgroundColor(int backgroundColor) {
getMutableBorder().setBackgroundColor(backgroundColor);
}
@Override
public void setBorderWidths(int index, float borderWidth) {
super.setBorderWidths(index, borderWidth);
int type = SPACING_TYPES[index];
getMutableBorder().setBorderWidth(type, PixelUtil.toPixelFromDIP(borderWidth));
}
@ReactProp(name = "nativeBackgroundAndroid")
public void setHotspot(@Nullable ReadableMap bg) {
if (bg != null) {
forceMountToView();
}
}
@ReactPropGroup(names = {
"borderColor", "borderLeftColor", "borderRightColor", "borderTopColor", "borderBottomColor"
}, customType = "Color", defaultDouble = Double.NaN)
public void setBorderColor(int index, double color) {
int type = SPACING_TYPES[index];
if (Double.isNaN(color)) {
getMutableBorder().resetBorderColor(type);
} else {
getMutableBorder().setBorderColor(type, (int) color);
}
}
@ReactProp(name = "borderRadius")
public void setBorderRadius(float borderRadius) {
mClipRadius = borderRadius;
if (mClipToBounds && borderRadius > DrawView.MINIMUM_ROUNDED_CLIPPING_VALUE) {
// mount to a view if we are overflow: hidden and are clipping, so that we can do one
// clipPath to clip all the children of this node (both DrawCommands and Views).
forceMountToView();
}
getMutableBorder().setBorderRadius(PixelUtil.toPixelFromDIP(borderRadius));
}
@ReactProp(name = "borderStyle")
public void setBorderStyle(@Nullable String borderStyle) {
getMutableBorder().setBorderStyle(borderStyle);
}
@ReactProp(name = "hitSlop")
public void setHitSlop(@Nullable ReadableMap hitSlop) {
if (hitSlop == null) {
mHitSlop = null;
} else {
mHitSlop = new Rect(
(int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("left")),
(int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("top")),
(int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("right")),
(int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("bottom")));
}
}
@ReactProp(name = "pointerEvents")
public void setPointerEvents(@Nullable String pointerEventsStr) {
forceMountToView();
}
@Override
/* package */ void updateNodeRegion(
float left,
float top,
float right,
float bottom,
boolean isVirtual) {
if (!getNodeRegion().matches(left, top, right, bottom, isVirtual)) {
setNodeRegion(mHitSlop == null ?
new NodeRegion(left, top, right, bottom, getReactTag(), isVirtual) :
new HitSlopNodeRegion(mHitSlop, left, top, right, bottom, getReactTag(), isVirtual));
}
}
private DrawBorder getMutableBorder() {
if (mDrawBorder == null) {
mDrawBorder = new DrawBorder();
} else if (mDrawBorder.isFrozen()) {
mDrawBorder = (DrawBorder) mDrawBorder.mutableCopy();
}
invalidate();
return mDrawBorder;
}
@Override
public boolean clipsSubviews() {
return mRemoveClippedSubviews;
}
}