Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Update require's from TouchableWin32 to be imports",
"packageName": "@office-iss/react-native-win32",
"email": "30809111+acoates-ms@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Center single line textinputs",
"packageName": "react-native-windows",
"email": "30809111+acoates-ms@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@ import {
} from './TouchableWin32.Types';
import { IKeyboardEvent } from '../View/ViewPropTypes';

const BoundingDimensions = require('./BoundingDimensions');
const Position = require('./Position');
// @ts-ignore
import BoundingDimensions from './BoundingDimensions';
// @ts-ignore
import Position from './Position';

const {findNodeHandle} = require('../../ReactNative/RendererProxy');
// @ts-ignore
import {findNodeHandle} from '../../ReactNative/RendererProxy';

/**
* Extracts a single touch, generally this is the active touch or touch that
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -381,9 +381,9 @@ exports[`TextInput Tests Text have cursorColor 1`] = `
"Brush Type": "ColorBrush",
"Color": "rgba(0, 128, 0, 255)",
},
"Offset": "83, 5, 0",
"Offset": "89, 6, 0",
"Opacity": 0,
"Size": "1, 19",
"Size": "1, 21",
"Visual Type": "SpriteVisual",
},
],
Expand Down Expand Up @@ -1884,9 +1884,9 @@ exports[`TextInput Tests TextInputs can clear on submit 1`] = `
"Brush Type": "ColorBrush",
"Color": "rgba(0, 0, 0, 255)",
},
"Offset": "5, 5, 0",
"Offset": "5, 6, 0",
"Opacity": 0,
"Size": "1, 19",
"Size": "1, 21",
"Visual Type": "SpriteVisual",
},
],
Expand Down Expand Up @@ -2805,9 +2805,9 @@ exports[`TextInput Tests TextInputs can have caretHidden 1`] = `
"Brush Type": "ColorBrush",
"Color": "rgba(0, 0, 0, 255)",
},
"Offset": "83, 5, 0",
"Offset": "89, 6, 0",
"Opacity": 0,
"Size": "1, 19",
"Size": "1, 21",
"Visual Type": "SpriteVisual",
},
],
Expand Down Expand Up @@ -4993,9 +4993,9 @@ exports[`TextInput Tests TextInputs can select text on focus 1`] = `
"Brush Type": "ColorBrush",
"Color": "rgba(0, 0, 0, 255)",
},
"Offset": "83, 5, 0",
"Offset": "89, 6, 0",
"Opacity": 0,
"Size": "1, 19",
"Size": "1, 21",
"Visual Type": "SpriteVisual",
},
],
Expand Down Expand Up @@ -5226,7 +5226,7 @@ exports[`TextInput Tests TextInputs can submit with custom key, multilined and s
},
"Offset": "5, 5, 0",
"Opacity": 0,
"Size": "1, 19",
"Size": "1, 21",
"Visual Type": "SpriteVisual",
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,8 @@ struct CompTextHost : public winrt::implements<CompTextHost, ITextHost> {
//@cmember Converts screen coordinates of a specified point to the client coordinates
BOOL TxScreenToClient(LPPOINT lppt) override {
winrt::Windows::Foundation::Point pt{static_cast<float>(lppt->x), static_cast<float>(lppt->y)};
pt.X -= m_outer->m_contentOffsetPx.x;
pt.Y -= m_outer->m_contentOffsetPx.y;
auto localpt = m_outer->ScreenToLocal(pt);
lppt->x = static_cast<LONG>(localpt.X);
lppt->y = static_cast<LONG>(localpt.Y);
Expand All @@ -255,9 +257,14 @@ struct CompTextHost : public winrt::implements<CompTextHost, ITextHost> {
//@cmember Converts the client coordinates of a specified point to screen coordinates
BOOL TxClientToScreen(LPPOINT lppt) override {
winrt::Windows::Foundation::Point pt{static_cast<float>(lppt->x), static_cast<float>(lppt->y)};

if (!m_outer->m_parent) {
return false;
}

auto screenpt = m_outer->LocalToScreen(pt);
lppt->x = static_cast<LONG>(screenpt.X);
lppt->y = static_cast<LONG>(screenpt.Y);
lppt->x = static_cast<LONG>(screenpt.X) + m_outer->m_contentOffsetPx.x;
lppt->y = static_cast<LONG>(screenpt.Y) + m_outer->m_contentOffsetPx.y;
return true;
}

Expand All @@ -276,20 +283,25 @@ struct CompTextHost : public winrt::implements<CompTextHost, ITextHost> {
//@cmember Retrieves the coordinates of a window's client area
HRESULT TxGetClientRect(LPRECT prc) override {
*prc = m_outer->getClientRect();

prc->top += m_outer->m_contentOffsetPx.y;
prc->bottom += m_outer->m_contentOffsetPx.y -
static_cast<LONG>(m_outer->m_layoutMetrics.contentInsets.bottom * m_outer->m_layoutMetrics.pointScaleFactor);
prc->left += m_outer->m_contentOffsetPx.x;
prc->right += m_outer->m_contentOffsetPx.x -
static_cast<LONG>(m_outer->m_layoutMetrics.contentInsets.right * m_outer->m_layoutMetrics.pointScaleFactor);

return S_OK;
}

//@cmember Get the view rectangle relative to the inset
HRESULT TxGetViewInset(LPRECT prc) override {
// Inset is in HIMETRIC
constexpr float HmPerInchF = 2540.0f;
constexpr float PointsPerInch = 96.0f;
constexpr float dipToHm = HmPerInchF / PointsPerInch;

prc->left = static_cast<LONG>(m_outer->m_layoutMetrics.contentInsets.left * dipToHm);
prc->top = static_cast<LONG>(m_outer->m_layoutMetrics.contentInsets.top * dipToHm);
prc->bottom = static_cast<LONG>(m_outer->m_layoutMetrics.contentInsets.bottom * dipToHm);
prc->right = static_cast<LONG>(m_outer->m_layoutMetrics.contentInsets.right * dipToHm);
prc->left = 0;
prc->top = 0;
prc->bottom = 0;
prc->right = 0;

return NOERROR;
}
Expand Down Expand Up @@ -492,11 +504,6 @@ AutoCorrectOffCallback(LANGID langid, const WCHAR *pszBefore, WCHAR *pszAfter, L
facebook::react::AttributedString WindowsTextInputComponentView::getAttributedString() const {
// Use BaseTextShadowNode to get attributed string from children

auto childTextAttributes = facebook::react::TextAttributes::defaultTextAttributes();
childTextAttributes.fontSizeMultiplier = m_fontSizeMultiplier;

childTextAttributes.apply(windowsTextInputProps().textAttributes);

auto attributedString = facebook::react::AttributedString{};
// auto attachments = facebook::react::BaseTextShadowNode::Attachments{};

Expand Down Expand Up @@ -1114,6 +1121,9 @@ void WindowsTextInputComponentView::updateProps(
!facebook::react::floatEquality(
oldTextInputProps.textAttributes.letterSpacing, newTextInputProps.textAttributes.letterSpacing) ||
oldTextInputProps.textAttributes.fontFamily != newTextInputProps.textAttributes.fontFamily ||
oldTextInputProps.textAttributes.fontStyle != newTextInputProps.textAttributes.fontStyle ||
oldTextInputProps.textAttributes.textDecorationLineType !=
newTextInputProps.textAttributes.textDecorationLineType ||
!facebook::react::floatEquality(
oldTextInputProps.textAttributes.maxFontSizeMultiplier,
newTextInputProps.textAttributes.maxFontSizeMultiplier)) {
Expand All @@ -1129,6 +1139,7 @@ void WindowsTextInputComponentView::updateProps(
}

if (oldTextInputProps.multiline != newTextInputProps.multiline) {
m_recalculateContentVerticalOffset = true;
m_multiline = newTextInputProps.multiline;
m_propBitsMask |= TXTBIT_MULTILINE | TXTBIT_WORDWRAP;
if (newTextInputProps.multiline) {
Expand Down Expand Up @@ -1278,6 +1289,10 @@ void WindowsTextInputComponentView::updateLayoutMetrics(
unsigned int newWidth = static_cast<unsigned int>(layoutMetrics.frame.size.width * layoutMetrics.pointScaleFactor);
unsigned int newHeight = static_cast<unsigned int>(layoutMetrics.frame.size.height * layoutMetrics.pointScaleFactor);

if (newHeight != m_imgHeight || oldLayoutMetrics.pointScaleFactor != layoutMetrics.pointScaleFactor) {
m_recalculateContentVerticalOffset = true;
}

if (newWidth != m_imgWidth || newHeight != m_imgHeight) {
m_drawingSurface = nullptr; // Invalidate surface if we get a size change
}
Expand Down Expand Up @@ -1416,6 +1431,8 @@ void WindowsTextInputComponentView::FinalizeUpdates(

void WindowsTextInputComponentView::UpdatePropertyBits() noexcept {
if (m_propBitsMask != 0) {
if ((m_propBits & TXTBIT_CHARFORMATCHANGE) == TXTBIT_CHARFORMATCHANGE)
m_recalculateContentVerticalOffset = true;
DrawBlock db(*this);
winrt::check_hresult(m_textServices->OnTxPropertyBitsChange(m_propBitsMask, m_propBits));
m_propBitsMask = 0;
Expand All @@ -1427,6 +1444,10 @@ void WindowsTextInputComponentView::InternalFinalize() noexcept {
if (m_mounted) {
UpdatePropertyBits();

if (m_recalculateContentVerticalOffset) {
calculateContentVerticalOffset();
}

ensureDrawingSurface();
if (m_needsRedraw) {
DrawText();
Expand Down Expand Up @@ -1488,12 +1509,6 @@ void WindowsTextInputComponentView::UpdateCharFormat() noexcept {
// m_crText = RemoveAlpha(fontDetails.FontColor);
// }

// set font face
// cfNew.dwMask |= CFM_FACE;
// NetUIWzCchCopy(cfNew.szFaceName, _countof(cfNew.szFaceName), fontDetails.FontName.c_str());
// cfNew.bPitchAndFamily = FF_DONTCARE;

// set font size -- 15 to convert twips to pt
const auto &props = windowsTextInputProps();
float fontSize =
(std::isnan(props.textAttributes.fontSize) ? facebook::react::TextAttributes::defaultTextAttributes().fontSize
Expand All @@ -1504,35 +1519,47 @@ void WindowsTextInputComponentView::UpdateCharFormat() noexcept {
fontSize *=
(maxFontSizeMultiplier >= 1.0f) ? std::min(maxFontSizeMultiplier, m_fontSizeMultiplier) : m_fontSizeMultiplier;

// TODO get fontSize from props.textAttributes, or defaultTextAttributes, or fragment?
cfNew.dwMask |= CFM_SIZE;
// set font size -- 15 to convert twips to pt
cfNew.yHeight = static_cast<LONG>(fontSize * 15);

// set bold
cfNew.dwMask |= CFM_WEIGHT;
cfNew.wWeight =
props.textAttributes.fontWeight ? static_cast<WORD>(*props.textAttributes.fontWeight) : DWRITE_FONT_WEIGHT_NORMAL;

// set font style
// cfNew.dwMask |= (CFM_ITALIC | CFM_STRIKEOUT | CFM_UNDERLINE);
// int dFontStyle = fontDetails.FontStyle;
// if (dFontStyle & FS_Italic) {
// cfNew.dwEffects |= CFE_ITALIC;
// }
// if (dFontStyle & FS_StrikeOut) {
// cfNew.dwEffects |= CFE_STRIKEOUT;
//}
// if (dFontStyle & FS_Underline) {
// cfNew.dwEffects |= CFE_UNDERLINE;
// }
// set font style (italic)
cfNew.dwMask |= CFM_ITALIC;
if (props.textAttributes.fontStyle == facebook::react::FontStyle::Italic ||
props.textAttributes.fontStyle == facebook::react::FontStyle::Oblique) {
cfNew.dwEffects |= CFE_ITALIC;
}

// set text decoration (underline and strikethrough)
cfNew.dwMask |= (CFM_UNDERLINE | CFM_STRIKEOUT);
if (props.textAttributes.textDecorationLineType.has_value()) {
auto decorationType = *props.textAttributes.textDecorationLineType;
if (decorationType == facebook::react::TextDecorationLineType::Underline ||
decorationType == facebook::react::TextDecorationLineType::UnderlineStrikethrough) {
cfNew.dwEffects |= CFE_UNDERLINE;
}
if (decorationType == facebook::react::TextDecorationLineType::Strikethrough ||
decorationType == facebook::react::TextDecorationLineType::UnderlineStrikethrough) {
cfNew.dwEffects |= CFE_STRIKEOUT;
}
}

// set font family
if (!props.textAttributes.fontFamily.empty()) {
cfNew.dwMask |= CFM_FACE;
std::wstring fontFamily =
std::wstring(props.textAttributes.fontFamily.begin(), props.textAttributes.fontFamily.end());
wcsncpy_s(cfNew.szFaceName, fontFamily.c_str(), LF_FACESIZE);
} else {
cfNew.dwMask |= CFM_FACE;
wcsncpy_s(cfNew.szFaceName, L"Segoe UI\0", LF_FACESIZE);
}
cfNew.bPitchAndFamily = FF_DONTCARE;

// set char offset
cfNew.dwMask |= CFM_OFFSET;
Expand All @@ -1541,7 +1568,8 @@ void WindowsTextInputComponentView::UpdateCharFormat() noexcept {
// set letter spacing
float letterSpacing = props.textAttributes.letterSpacing;
if (!std::isnan(letterSpacing)) {
updateLetterSpacing(letterSpacing);
cfNew.dwMask |= CFM_SPACING;
cfNew.sSpacing = static_cast<SHORT>(letterSpacing * 20); // Convert to TWIPS
}

// set charset
Expand Down Expand Up @@ -1657,7 +1685,7 @@ winrt::com_ptr<::IDWriteTextLayout> WindowsTextInputComponentView::CreatePlaceho
const auto &props = windowsTextInputProps();
facebook::react::TextAttributes textAttributes = props.textAttributes;
if (std::isnan(props.textAttributes.fontSize)) {
textAttributes.fontSize = 12.0f;
facebook::react::TextAttributes::defaultTextAttributes().fontSize;
}
textAttributes.fontSizeMultiplier = m_fontSizeMultiplier;
fragment1.string = props.placeholder;
Expand All @@ -1674,6 +1702,26 @@ winrt::com_ptr<::IDWriteTextLayout> WindowsTextInputComponentView::CreatePlaceho
return textLayout;
}

void WindowsTextInputComponentView::calculateContentVerticalOffset() noexcept {
m_recalculateContentVerticalOffset = false;

const auto &props = windowsTextInputProps();

m_contentOffsetPx = {
static_cast<LONG>(m_layoutMetrics.contentInsets.left * m_layoutMetrics.pointScaleFactor),
static_cast<LONG>(m_layoutMetrics.contentInsets.top * m_layoutMetrics.pointScaleFactor)};

if (props.multiline) {
// Align to the top for multiline
return;
}

auto [contentWidth, contentHeight] = GetContentSize();

m_contentOffsetPx.y += static_cast<LONG>(std::round(
((m_layoutMetrics.getContentFrame().size.height - contentHeight) / 2) * m_layoutMetrics.pointScaleFactor));
}

void WindowsTextInputComponentView::DrawText() noexcept {
m_needsRedraw = true;
if (m_cDrawBlock || theme()->IsEmpty() || !m_textServices) {
Expand All @@ -1699,16 +1747,13 @@ void WindowsTextInputComponentView::DrawText() noexcept {
assert(d2dDeviceContext->GetUnitMode() == D2D1_UNIT_MODE_DIPS);

RECTL rc{
static_cast<LONG>(offset.x),
static_cast<LONG>(offset.y),
static_cast<LONG>(offset.x) + static_cast<LONG>(m_imgWidth),
static_cast<LONG>(offset.y) + static_cast<LONG>(m_imgHeight)};
offset.x + m_contentOffsetPx.x,
offset.y + m_contentOffsetPx.y,
offset.x + m_contentOffsetPx.x + static_cast<LONG>(m_imgWidth),
offset.y + m_contentOffsetPx.y + static_cast<LONG>(m_imgHeight)};

RECT rcClient{
static_cast<LONG>(offset.x),
static_cast<LONG>(offset.y),
static_cast<LONG>(offset.x) + static_cast<LONG>(m_imgWidth),
static_cast<LONG>(offset.y) + static_cast<LONG>(m_imgHeight)};
offset.x, offset.y, offset.x + static_cast<LONG>(m_imgWidth), offset.y + static_cast<LONG>(m_imgHeight)};

{
m_cDrawBlock++; // Dont use AutoDrawBlock as we are already in draw, and dont need to draw again.
Expand Down Expand Up @@ -1763,8 +1808,8 @@ void WindowsTextInputComponentView::DrawText() noexcept {
// draw text
d2dDeviceContext->DrawTextLayout(
D2D1::Point2F(
static_cast<FLOAT>((offset.x + m_layoutMetrics.contentInsets.left) / m_layoutMetrics.pointScaleFactor),
static_cast<FLOAT>((offset.y + m_layoutMetrics.contentInsets.top) / m_layoutMetrics.pointScaleFactor)),
static_cast<FLOAT>(offset.x + m_contentOffsetPx.x) / m_layoutMetrics.pointScaleFactor,
static_cast<FLOAT>(offset.y + m_contentOffsetPx.y) / m_layoutMetrics.pointScaleFactor),
textLayout.get(),
brush.get(),
D2D1_DRAW_TEXT_OPTIONS_ENABLE_COLOR_FONT);
Expand Down Expand Up @@ -1840,22 +1885,6 @@ void WindowsTextInputComponentView::autoCapitalizeOnUpdateProps(
}
}

void WindowsTextInputComponentView::updateLetterSpacing(float letterSpacing) noexcept {
CHARFORMAT2W cf = {};
cf.cbSize = sizeof(CHARFORMAT2W);
cf.dwMask = CFM_SPACING;
cf.sSpacing = static_cast<SHORT>(letterSpacing * 20); // Convert to TWIPS

LRESULT res;

// Apply to all existing text like placeholder
winrt::check_hresult(m_textServices->TxSendMessage(EM_SETCHARFORMAT, SCF_ALL, reinterpret_cast<LPARAM>(&cf), &res));

// Apply to future text input
winrt::check_hresult(
m_textServices->TxSendMessage(EM_SETCHARFORMAT, SCF_SELECTION, reinterpret_cast<LPARAM>(&cf), &res));
}

void WindowsTextInputComponentView::updateAutoCorrect(bool enable) noexcept {
LRESULT lresult;
winrt::check_hresult(m_textServices->TxSendMessage(
Expand Down
Loading
Loading