Skip to content

Commit

Permalink
Adding support for borders to UILabel and UIButton (via CALayer and t…
Browse files Browse the repository at this point in the history
…he CoreAnimation/UIKit composition layer). Note that we still don't have border support on basic CALayers, because we haven't needed to add them yet, but the plumbing is in now place to add them when needed.

Fixes microsoft#1884.
  • Loading branch information
jaredhms committed Feb 13, 2017
1 parent 28ec7c2 commit a04151e
Show file tree
Hide file tree
Showing 15 changed files with 303 additions and 74 deletions.
54 changes: 22 additions & 32 deletions Frameworks/QuartzCore/CALayer.mm
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,6 @@ static void DoDisplayList(CALayer* layer) {
_undefinedKeys = nil;
_actions = nil;
CGColorRelease(_backgroundColor);
CGColorRelease(_borderColor);
_name = nil;
if (_animations) {
[_animations release];
Expand Down Expand Up @@ -1582,64 +1581,55 @@ - (CGColorRef)backgroundColor {
return priv->_backgroundColor;
}

- (void)_setContentColor:(CGColorRef)newColor {
UNIMPLEMENTED();
}

/**
@Status Stub
@Status Interoperable
*/
- (void)setBorderColor:(CGColorRef)color {
UNIMPLEMENTED();
if (color != nil) {
priv->borderColor = *[static_cast<UIColor*>(color) _getColors];
} else {
_ClearColorQuad(priv->borderColor);
}

CGColorRef old = priv->_borderColor;
priv->_borderColor = CGColorRetain(color);
CGColorRelease(old);
// Set the border color via CATransaction
[CATransaction _setPropertyForLayer:self name:@"borderColor" value:(NSObject*)color];
[self setNeedsDisplay];
}

/**
@Status Stub
@Status Interoperable
*/
- (CGColorRef)borderColor {
UNIMPLEMENTED();
return priv->_borderColor;
// Grab the current border color directly off of the layer proxy
return [(UIColor*)priv->_layerProxy->GetPropertyValue("borderColor") CGColor];
}

/**
@Status Stub
@Status Interoperable
*/
- (void)setBorderWidth:(float)width {
UNIMPLEMENTED();
priv->borderWidth = width;
// Set the border width via CATransaction
[CATransaction _setPropertyForLayer:self name:@"borderWidth" value:[NSNumber numberWithFloat:width]];
[self setNeedsDisplay];
}

/**
@Status Stub
@Status Interoperable
*/
- (float)borderWidth {
UNIMPLEMENTED();
return priv->borderWidth;
// Grab the current border width directly off of the layer proxy
return [(NSNumber*)priv->_layerProxy->GetPropertyValue("borderWidth") floatValue];
}

/**
@Status Stub
@Status NotInPlan
@Notes Rounded corners with clipped children are not currently achievable in Xaml.
*/
- (void)setCornerRadius:(float)radius {
UNIMPLEMENTED();
priv->cornerRadius = radius;
UNIMPLEMENTED_WITH_MSG("Rounded corners with clipped children are not achievable in Xaml.");
}

/**
@Status Stub
@Status NotInPlan
@Notes Rounded corners with clipped children are not currently achievable in Xaml.
*/
- (float)cornerRadius {
UNIMPLEMENTED();
return priv->cornerRadius;
UNIMPLEMENTED_WITH_MSG("Rounded corners with clipped children are not achievable in Xaml.");
return StubReturn();
}

/**
Expand Down Expand Up @@ -2518,7 +2508,7 @@ + (CGRect)convertRect:(CGRect)pos fromLayer:(CALayer*)fromLayer toLayer:(CALayer
return ret;
}

- (NSObject*)presentationValueForKey:(NSString*)key {
- (NSObject*)_presentationValueForKey:(NSString*)key {
return reinterpret_cast<NSObject*>(priv->_layerProxy->GetPropertyValue([key UTF8String]));
}

Expand Down
10 changes: 10 additions & 0 deletions Frameworks/UIKit.Xaml/Button.xaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ Canvas^ Button::SublayerCanvas::get() {
return _contentCanvas;
}

// Accessor for the LayerProperty that manages the BorderBrush of this button
Private::CoreAnimation::LayerProperty^ Button::GetBorderBrushProperty() {
return ref new Private::CoreAnimation::LayerProperty(_border, _border->BorderBrushProperty);
}

// Accessor for the LayerProperty that manages the BorderThickness of this button
Private::CoreAnimation::LayerProperty^ Button::GetBorderThicknessProperty() {
return ref new Private::CoreAnimation::LayerProperty(_border, _border->BorderThicknessProperty);
}

void Button::OnPointerPressed(PointerRoutedEventArgs^ e) {
// Call the pointer hook if it exists
if (_pointerPressedHook) {
Expand Down
6 changes: 6 additions & 0 deletions Frameworks/UIKit.Xaml/Button.xaml.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ public ref class Button sealed : public Private::CoreAnimation::ILayer {
Windows::UI::Xaml::Controls::Canvas^ get();
}

// Accessor for the LayerProperty that manages the BorderBrush of this button
virtual Private::CoreAnimation::LayerProperty^ GetBorderBrushProperty();

// Accessor for the LayerProperty that manages the BorderThickness of this button
virtual Private::CoreAnimation::LayerProperty^ GetBorderThicknessProperty();

internal:
void HookPointerEvents(
const Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::Input::IPointerEventHandler>& pointerPressedHook,
Expand Down
35 changes: 34 additions & 1 deletion Frameworks/UIKit.Xaml/Label.xaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,45 @@ Canvas^ Label::SublayerCanvas::get() {
if (!_sublayerCanvas) {
_sublayerCanvas = ref new Canvas();
_sublayerCanvas->Name = "Sublayers";
Children->Append(_sublayerCanvas);

// If we have a border make sure the sublayer canvas is inserted before it
if (_border) {
unsigned int insertIndex = 0;
Children->IndexOf(_border, &insertIndex);
Children->InsertAt(insertIndex, _sublayerCanvas);
} else {
// Just add the sublayer canvas to the end because we don't yet have a border on this element
Children->Append(_sublayerCanvas);
}
}

return _sublayerCanvas;
}

Border^ Label::_GetBorder() {
if (!_border) {
// We always want the border added to the end of the Children collection
_border = ref new Border();
Children->Append(_border);
}

return _border;
}

// Accessor for the LayerProperty that manages the BorderBrush of this label
Private::CoreAnimation::LayerProperty^ Label::GetBorderBrushProperty() {
// Make sure we have a border element, and return it along with its associated border property
Border^ border = _GetBorder();
return ref new Private::CoreAnimation::LayerProperty(border, border->BorderBrushProperty);
}

// Accessor for the LayerProperty that manages the BorderThickness of this label
Private::CoreAnimation::LayerProperty^ Label::GetBorderThicknessProperty() {
// Make sure we have a border element, and return it along with its associated border property
Border^ border = _GetBorder();
return ref new Private::CoreAnimation::LayerProperty(border, border->BorderThicknessProperty);
}

Windows::Foundation::Size Label::ArrangeOverride(Windows::Foundation::Size finalSize) {
// Make sure we render vertically-centered text if possible, else cap at the containing layer's height.
// TODO: Issue #1946: Do we actually need this call to Measure?
Expand Down
9 changes: 9 additions & 0 deletions Frameworks/UIKit.Xaml/Label.xaml.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,24 @@ public ref class Label sealed : public Private::CoreAnimation::ILayer {
Windows::UI::Xaml::Controls::Canvas^ get();
}

// Accessor for the LayerProperty that manages the BorderBrush of this label
virtual Private::CoreAnimation::LayerProperty^ GetBorderBrushProperty();

// Accessor for the LayerProperty that manages the BorderThickness of this label
virtual Private::CoreAnimation::LayerProperty^ GetBorderThicknessProperty();

internal:
property Windows::UI::Xaml::Controls::TextBlock^ TextBlock {
Windows::UI::Xaml::Controls::TextBlock^ get();
}

private:
Windows::UI::Xaml::Controls::Border^ _GetBorder();

// Layer elements; created on demand
Windows::UI::Xaml::Controls::Image^ _content;
Windows::UI::Xaml::Controls::Canvas^ _sublayerCanvas;
Windows::UI::Xaml::Controls::Border^ _border;
};

} /* Xaml*/
Expand Down
25 changes: 25 additions & 0 deletions Frameworks/UIKit.Xaml/Layer.xaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ DependencyProperty^ Layer::s_layerContentProperty = nullptr;
DependencyProperty^ Layer::s_sublayerCanvasProperty = nullptr;
bool Layer::s_dependencyPropertiesRegistered = false;

LayerProperty::LayerProperty(DependencyObject^ target, DependencyProperty^ property) : _target(target), _property(property) {
}

void LayerProperty::SetValue(Platform::Object^ value) {
// Set the specified value on our underlying target/property pair
_target->SetValue(_property, value);
}

Platform::Object^ LayerProperty::GetValue() {
// Retrieve the current value from our underlying target/property pair
return _target->GetValue(_property);
}

Layer::Layer() {
InitializeComponent();

Expand Down Expand Up @@ -72,6 +85,18 @@ Canvas^ Layer::SublayerCanvas::get() {
return this;
}

// Accessor for the LayerProperty that manages the BorderBrush of this layer
LayerProperty^ Layer::GetBorderBrushProperty() {
// We don't support borders on basic layers yet, because Canvas doesn't support one intrinsically
return nullptr;
}

// Accessor for the LayerProperty that manages the BorderThickness of this layer
LayerProperty^ Layer::GetBorderThicknessProperty() {
// We don't support borders on basic layers yet, because Canvas doesn't support one intrinsically
return nullptr;
}

DependencyProperty^ Layer::LayerContentProperty::get() {
return s_layerContentProperty;
}
Expand Down
27 changes: 27 additions & 0 deletions Frameworks/UIKit.Xaml/Layer.xaml.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,21 @@ namespace Xaml {
namespace Private {
namespace CoreAnimation {

// Pairs a DependencyProperty and its associated DependencyObject for setting/getting values on objects within an ILayer instance.
// For example, can wrap an internal FrameworkElement and its associated BorderBrushProperty.
[Windows::Foundation::Metadata::WebHostHidden]
public ref class LayerProperty sealed {
public:
LayerProperty(Windows::UI::Xaml::DependencyObject^ target, Windows::UI::Xaml::DependencyProperty^ property);

void SetValue(Platform::Object^ value);
Platform::Object^ GetValue();

private:
Windows::UI::Xaml::DependencyObject^ _target;
Windows::UI::Xaml::DependencyProperty^ _property;
};

[Windows::Foundation::Metadata::WebHostHidden]
public interface class ILayer {
public:
Expand All @@ -41,6 +56,12 @@ public interface class ILayer {
property Windows::UI::Xaml::Controls::Canvas^ SublayerCanvas {
Windows::UI::Xaml::Controls::Canvas^ get();
}

// Accessor for the LayerProperty that manages the BorderBrush of this layer
LayerProperty^ GetBorderBrushProperty();

// Accessor for the LayerProperty that manages the BorderThickness of this layer
LayerProperty^ GetBorderThicknessProperty();
};

[Windows::Foundation::Metadata::WebHostHidden]
Expand All @@ -63,6 +84,12 @@ public ref class Layer sealed : public ILayer {
Windows::UI::Xaml::Controls::Canvas^ get();
}

// Accessor for the LayerProperty that manages the BorderBrush of this layer
virtual LayerProperty^ GetBorderBrushProperty();

// Accessor for the LayerProperty that manages the BorderThickness of this layer
virtual LayerProperty^ GetBorderThicknessProperty();

// Allows arbitrary framework elements to opt-into hosting layer content
static property Windows::UI::Xaml::DependencyProperty^ LayerContentProperty {
Windows::UI::Xaml::DependencyProperty^ get();
Expand Down
Loading

0 comments on commit a04151e

Please sign in to comment.