1 /* 2 * Copyright 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.compose.foundation.text.modifiers 18 19 import androidx.compose.foundation.text.DefaultMinLines 20 import androidx.compose.foundation.text.TextAutoSize 21 import androidx.compose.ui.geometry.Rect 22 import androidx.compose.ui.graphics.ColorProducer 23 import androidx.compose.ui.node.ModifierNodeElement 24 import androidx.compose.ui.platform.InspectorInfo 25 import androidx.compose.ui.text.AnnotatedString 26 import androidx.compose.ui.text.Placeholder 27 import androidx.compose.ui.text.TextLayoutResult 28 import androidx.compose.ui.text.TextStyle 29 import androidx.compose.ui.text.font.FontFamily 30 import androidx.compose.ui.text.style.TextOverflow 31 32 /** 33 * Modifier element for any Text with [AnnotatedString] or [onTextLayout] parameters 34 * 35 * This is slower than [TextAnnotatedStringElement] 36 */ 37 internal class TextAnnotatedStringElement( 38 private val text: AnnotatedString, 39 private val style: TextStyle, 40 private val fontFamilyResolver: FontFamily.Resolver, 41 private val onTextLayout: ((TextLayoutResult) -> Unit)? = null, 42 private val overflow: TextOverflow = TextOverflow.Clip, 43 private val softWrap: Boolean = true, 44 private val maxLines: Int = Int.MAX_VALUE, 45 private val minLines: Int = DefaultMinLines, 46 private val placeholders: List<AnnotatedString.Range<Placeholder>>? = null, 47 private val onPlaceholderLayout: ((List<Rect?>) -> Unit)? = null, 48 private val selectionController: SelectionController? = null, 49 private val color: ColorProducer? = null, 50 private val autoSize: TextAutoSize? = null, 51 private val onShowTranslation: ((TextAnnotatedStringNode.TextSubstitutionValue) -> Unit)? = null 52 ) : ModifierNodeElement<TextAnnotatedStringNode>() { 53 createnull54 override fun create(): TextAnnotatedStringNode = 55 TextAnnotatedStringNode( 56 text, 57 style, 58 fontFamilyResolver, 59 onTextLayout, 60 overflow, 61 softWrap, 62 maxLines, 63 minLines, 64 placeholders, 65 onPlaceholderLayout, 66 selectionController, 67 color, 68 autoSize, 69 onShowTranslation 70 ) 71 72 override fun update(node: TextAnnotatedStringNode) { 73 node.doInvalidations( 74 drawChanged = node.updateDraw(color, style), 75 textChanged = node.updateText(text = text), 76 layoutChanged = 77 node.updateLayoutRelatedArgs( 78 style = style, 79 placeholders = placeholders, 80 minLines = minLines, 81 maxLines = maxLines, 82 softWrap = softWrap, 83 fontFamilyResolver = fontFamilyResolver, 84 overflow = overflow, 85 autoSize = autoSize 86 ), 87 callbacksChanged = 88 node.updateCallbacks( 89 onTextLayout = onTextLayout, 90 onPlaceholderLayout = onPlaceholderLayout, 91 selectionController = selectionController, 92 onShowTranslation = onShowTranslation 93 ) 94 ) 95 } 96 equalsnull97 override fun equals(other: Any?): Boolean { 98 if (this === other) return true 99 100 if (other !is TextAnnotatedStringElement) return false 101 102 // these three are most likely to actually change 103 if (color != other.color) return false 104 if (text != other.text) return false /* expensive to check, do it after color */ 105 if (style != other.style) return false 106 if (placeholders != other.placeholders) return false 107 108 // these are equally unlikely to change 109 if (fontFamilyResolver != other.fontFamilyResolver) return false 110 if (onTextLayout !== other.onTextLayout) return false 111 if (onShowTranslation !== other.onShowTranslation) return false 112 if (overflow != other.overflow) return false 113 if (softWrap != other.softWrap) return false 114 if (maxLines != other.maxLines) return false 115 if (minLines != other.minLines) return false 116 117 // these never change, but check anyway for correctness 118 if (onPlaceholderLayout !== other.onPlaceholderLayout) return false 119 if (selectionController != other.selectionController) return false 120 121 return true 122 } 123 hashCodenull124 override fun hashCode(): Int { 125 var result = text.hashCode() 126 result = 31 * result + style.hashCode() 127 result = 31 * result + fontFamilyResolver.hashCode() 128 result = 31 * result + (onTextLayout?.hashCode() ?: 0) 129 result = 31 * result + overflow.hashCode() 130 result = 31 * result + softWrap.hashCode() 131 result = 31 * result + maxLines 132 result = 31 * result + minLines 133 result = 31 * result + (placeholders?.hashCode() ?: 0) 134 result = 31 * result + (onPlaceholderLayout?.hashCode() ?: 0) 135 result = 31 * result + (selectionController?.hashCode() ?: 0) 136 result = 31 * result + (color?.hashCode() ?: 0) 137 result = 31 * result + (onShowTranslation?.hashCode() ?: 0) 138 return result 139 } 140 inspectablePropertiesnull141 override fun InspectorInfo.inspectableProperties() { 142 // Show nothing in the inspector. 143 } 144 } 145