1 /* 2 * Copyright 2024 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.ui.text 18 19 import androidx.compose.ui.geometry.CornerRadius 20 import androidx.compose.ui.geometry.RoundRect 21 import androidx.compose.ui.geometry.Size 22 import androidx.compose.ui.geometry.toRect 23 import androidx.compose.ui.graphics.Brush 24 import androidx.compose.ui.graphics.Outline 25 import androidx.compose.ui.graphics.Shape 26 import androidx.compose.ui.graphics.drawscope.DrawStyle 27 import androidx.compose.ui.graphics.drawscope.Fill 28 import androidx.compose.ui.unit.Density 29 import androidx.compose.ui.unit.LayoutDirection 30 import androidx.compose.ui.unit.TextUnit 31 import androidx.compose.ui.unit.em 32 33 /** 34 * A bullet annotation applied to the AnnotatedString that draws a bullet. 35 * 36 * Note that it's up to the caller of this API to make sure there's enough space between the edge of 37 * the text composable and the start of the paragraph inside that composable to fit the bullet with 38 * its padding. 39 * 40 * @param shape a shape of the bullet to draw 41 * @param size a size of the bullet 42 * @param padding a padding between the end of the bullet and the start of the paragraph 43 * @param brush a brush to draw a bullet with 44 * @param alpha an alpha to apply when drawing a bullet 45 * @param drawStyle defines the draw style of the bullet, e.g. a fill or an outline 46 */ 47 internal class Bullet( 48 val shape: Shape, 49 val size: TextUnit, // Make TextUnitSize or something similar when making public 50 val padding: TextUnit, 51 val brush: Brush?, 52 val alpha: Float, 53 val drawStyle: DrawStyle 54 ) : AnnotatedString.Annotation { 55 /** Copies the existing [Bullet] replacing some of the fields as desired. */ copynull56 fun copy( 57 shape: Shape = this.shape, 58 size: TextUnit = this.size, 59 padding: TextUnit = this.padding, 60 brush: Brush? = this.brush, 61 alpha: Float = this.alpha, 62 drawStyle: DrawStyle = this.drawStyle, 63 ) = Bullet(shape, size, padding, brush, alpha, drawStyle) 64 65 override fun equals(other: Any?): Boolean { 66 if (this === other) return true 67 if (other == null || other !is Bullet) return false 68 69 if (shape != other.shape) return false 70 if (size != other.size) return false 71 if (padding != other.padding) return false 72 if (brush != other.brush) return false 73 if (alpha != other.alpha) return false 74 if (drawStyle != other.drawStyle) return false 75 76 return true 77 } 78 hashCodenull79 override fun hashCode(): Int { 80 var result = shape.hashCode() 81 result = 31 * result + size.hashCode() 82 result = 31 * result + padding.hashCode() 83 result = 31 * result + brush.hashCode() 84 result = 31 * result + alpha.hashCode() 85 result = 31 * result + drawStyle.hashCode() 86 return result 87 } 88 toStringnull89 override fun toString(): String { 90 return "Bullet(shape=$shape, size=$size, padding=$padding, brush=$brush, alpha=$alpha, drawStyle=$drawStyle)" 91 } 92 } 93 94 /** Default indentation between the start edge of the Text composable and start of paragraph */ 95 internal val DefaultBulletIndentation = 1.em 96 /** Default size of the bullet */ 97 private val DefaultBulletSize = 0.25.em 98 /** Default padding between a bullet and start of a paragraph */ 99 private val DefaultBulletPadding = 0.25.em 100 /** Default bullet used in AnnotatedString's bullet list */ 101 internal val DefaultBullet = 102 Bullet(CircleShape, DefaultBulletSize, DefaultBulletPadding, null, 1f, Fill) 103 104 private object CircleShape : Shape { createOutlinenull105 override fun createOutline( 106 size: Size, 107 layoutDirection: LayoutDirection, 108 density: Density 109 ): Outline { 110 val cornerRadius = CornerRadius(size.minDimension / 2f) 111 return Outline.Rounded( 112 RoundRect( 113 rect = size.toRect(), 114 topLeft = cornerRadius, 115 topRight = cornerRadius, 116 bottomRight = cornerRadius, 117 bottomLeft = cornerRadius 118 ) 119 ) 120 } 121 } 122